Repository navigation
Conversation
… (review needed) (Agent-Field#966) * engine: an idle conversation on an older build is named on the way in A host one build behind holding only an IDLE conversation — the turn finished, the person stepped away — was asked to go, went, and the window opened on the fresh build without a word. The busy-host notice from Agent-Field#691 covered work in flight, but a conversation merely kept warm read as not busy, so the person was never told the engine answering them had been a build behind. They debugged a fix that had simply not reached the conversation yet. The notice is now owed whenever the older same-wire build is the one answering, and it names what was held: still holding work, or only holding the conversation. A host that went quietly says it was an older build and that it is current now. * changes: entry for Agent-Field#966 * engine: the headless --once road carries the stale-host notice on stderr The notice is joined into the surface's entry notice, but --once opens no surface, so a scripted caller against an idle stale host heard nothing — the same silence the interactive road just fixed. It goes to stderr, the channel a scripted caller reads, leaving stdout to the answer alone.
…reach their page first (Agent-Field#978) * manual: two cold questions reach their page first instead of fourth, so the floor has margin MEASURED FIRST, on dev c495991 with the gate green: 8 of the 22 held-out questions reach their page first, 9 reach it only within the top four, 5 miss, and the floor is 17 = 8 + 9 exactly. So the floor did not have one thin probe — it had NINE simultaneously load-bearing ones, and any of the nine slipping out of fourth place reddens every open pull request. That is what cost four lanes an evening: Agent-Field#933 lost one question by a hair to a section about a tick's cell, and the gate reported an aggregate with no per-question ownership, so it took a bisect to find out which. Two of the three fourth-place probes are now first: how do I send it a photo 4th -> 1st attaching-files how do I tell it which project to work on 4th -> 1st choosing-a-folder held out first 10/22 -> 12/22 · within top 4 18/22 -> 18/22 the hundred-probe plain table unchanged, nothing lost a place EACH WAS MEASURED AND ONLY THE FORM THAT MOVED WAS KEPT. attaching-files took the asker's words into its EXISTING heading and went first. choosing-a-folder did NOT move that way — the same edit to its heading left it fourth — because its `/folder` section is four thousand characters and loses on length normalisation however many of the asker's words the heading carries. A short section of its own took it first. That is the form Agent-Field#973 proved works, and the correction it forced on the folklore this repository was passing around: a new `## ` heading is a HAZARD to be measured, not a prohibition to be obeyed. What is forbidden is adding one and trusting it. AND THE NEW SECTION SAYS WHAT THE PAGE SAYS. The first draft claimed the chosen folder's name is on the status line, which contradicts this page's own law five hundred lines down — what choosing a folder does is make the conversation ABOUT it, while where aforge is standing does not move. Corrected before it shipped, and it points at the section that owns the distinction rather than restating it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(changes): number the entry with the pull request it belongs to Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(changes): the length cap and the retrieval floor are one law, not two Lane P's reframing of this change's own finding, and it is better than the finding was. I had written "a long section resists its heading". What is actually true is that CLAUDE.md's "keep each section under ~2000 characters and self-contained" IS the retrieval rule: BM25 normalises by length, so a section past the cap is already hard to reach whatever its heading says. Measured on this page — the `/folder` section is 3825 characters and would not move to first place however many of the asker's words its heading carried, while a 600-character section on the same page took the same question to first. choosing-a-folder.md has nine sections over the cap, up to 5079. That matters because of WHEN each rule can be followed. "Measure both forms" only helps somebody who already has a retrieval failure to diagnose. "Keep the section under two thousand characters" is a rule they can follow while writing, before anything is red — and it now has a measured reason rather than reading as a preference about how much prose a person wants at once. It also gives the choice between the two forms a cheap test instead of judgement: `wc -c` the section. Under the cap, put the asker's words in the heading. Over it, split the section — which fixes both laws at once — or write a short one beside it. Splitting is the better instrument where there is room, because an over-cap section is a defect on its own terms and not only when a probe finds it. Not done here: nine sections is its own piece of work. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(changes): name the section this change checked its claim against Lane P's proposed shape for the one failure the manual gates cannot catch, tried here on the change that found the need for it rather than argued about. CLAUDE.md is explicit that the gates check a name is MENTIONED and never that the claim around it is true — a tool named in a "what aforge cannot do" section satisfies them perfectly while lying. It also already obliges a lane landing a capability to grep the corpus for the old denial. So the honest statement is not that there is no mechanism; it is that there is a stated obligation with nothing behind it. This entry now names the section it checked against. It is not a gate and could not be made into one cheaply. It is a prompt to do the read, written where a reviewer can see whether it was done — and the read is what caught this change's own false sentence, which no test in this repository would have. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…-Field#917) * task: c code recommendation Co-Authored-By: aforge <agentfield-bot@users.noreply.github.com> * Drop the since-you-left heading gloss as redundant with the heading itself * Remove the needs-you heading gloss — its group line already explains the panel --------- Co-authored-by: aforge <aforge@localhost> Co-authored-by: aforge <agentfield-bot@users.noreply.github.com>
) * A split drawing reaches the boundary its own cut opened A mark's drawing rides beside the next step and its one power over the work is the interruption: cut the request in flight so the boundary where the drawing can be SPENT arrives at once. Two orderings took that promise away, and both ended the same way — the turn paid for a whole extra step, and where that step was its last the drawing was written down as a carry-on and nothing was handed anywhere (Agent-Field#956). The reading published its answer only once `act` had RETURNED, so the boundary the cut bought read the reading as still in flight and let it pass; `take` is non-blocking by construction and cannot wait for it. The answer is published first now, and one claim (`sidecar.spent`) orders the interruption against the taker: whichever arrives first is the one that happens, so a reading whose answer has already reached a boundary raises no interruption into whatever the turn does next. And a cut that arrived between one step ending and the next beginning found nothing to cut and was dropped. Which cuts may be dropped is a property of the reading behind them and is declared by the cause (`boundaryCut`): a recall's block is in the transcript before its cut is raised, so the request being assembled carries it either way, while a drawing rides no transcript at all. So a boundary cut is OWED rather than spent on nothing, and `beginGeneration` — already the one place that decides whether there is anything to cut — spends it the instant there is. It belongs to the turn that asked for it, by number, so a cut one turn never spent cannot reach the next person's message. And on the one road where a drawing genuinely lands too late — a turn that answered in words has no boundary after it — the row says what the reading said rather than the opposite of it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * docs: the change entry for the split drawing Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * The claim gates the interruption, and a cut nobody needs is withdrawn Review of Agent-Field#962 found three things, and the first is a path this change made worse than it found it. sidecar.spent narrows the window where an interruption is delivered for an answer a boundary has already taken; it does not close it. Between the settle closing and the claim being made, the interruption can still win while a taker at that same boundary takes anyway. Nothing is lost — the drawing is in hand — but at a boundary there is no live generation, so the cut is now OWED rather than dropped, and on the arms where the turn takes the drawing and carries on (`handOverRunningTurn(...).moved == false`, `checkpointSettle`'s `ctx.Err()`) it stops the next step for a reading that has already been read. Before this PR the same race was a harmless drop. So the boundary that takes the drawing withdraws the cut it no longer needs (`Agent.dropOwedCut`), which is exact rather than racy: the take and the spend are both on the turn's own goroutine. And `spent`'s doc says what it does — it gates the interruption, it does not order the take. The structural law was satisfied by a rename: it matched the identifiers `close` and `act`, went green when no call named `act` was found, and accepted any channel close. It now finds the reading and the interruption by their SHAPE — the reading answers, the interruption does not — requires the settle to be the channel closed, and fails closed when the door never delivers its interruption at all. And the claim now has a test in the direction it exists for: a taker that has claimed an answer raises no interruption, plus the withdrawal and the fact that one reading never withdraws another's cut. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: the change entry names the claim's shape and Agent-Field#984 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* lane: a running stream teaches the ledger mid-stream, in non-overlapping windows Every lane.Sighting was built at settlement, so a stream producing tokens for minutes taught the belief the chooser ranks on nothing until it closed. The 14:32 retry of 2026-09-11 picked the same collapsed Morph endpoint the 14:29 call was still being throttled by, because the belief still described that machine's morning. The read loop already holds the live figures; it now folds a partial sighting in at most once a minute, each window covering only the span since the one before it, and the settlement sighting is rebased to cover only the tail no partial claimed. One stream is one measurement, told in chapters, never the same span twice. Issue Agent-Field#891 §1. PR Agent-Field#924 took the live-wire rescue; this is the teaching seam it deliberately did not. * changes: entry for Agent-Field#964
…ask beside its worker arms it (Agent-Field#958) (Agent-Field#987) * A refusal is about the parts, not the width: the judge that reads a task beside its worker arms it A `/task` the sizing judge called wide, whose first set of parts the reviewer then read together and refused, ran to the end of its life with no way to divide at all — however much of the material it opened, and however plainly the parts were there. The judge used to answer before the node was admitted, so its yes was one of armDivision's signals and the worker was CONSTRUCTED holding divide_work; once the judge moved beside the worker, so that nobody waits through it, that yes arrived after the belt was built and did nothing but draw parts. A refusal is a finding about the parts that were drawn, and it never un-judged the width. The yes is the arming again, through one door. armDivisionBeside banks the answer where the arming reads it and asks armDivision the question admission asks — so a harness design, a quick task, a part of somebody else's division and work already armed are refused by the very lines that refuse them at admission, rather than by a second list that would drift from the first. On a yes it writes the word through TaskNode.armAfterAdmission, the only writer of that word outside admission, then appends divide_work to the running belt through armFamily and re-renders the system prompt through rerenderSystemLocked: in that order, off that one write, so the belt and the prompt cannot be built from different answers. It happens before the parts are weighed, so every road out of the weighing — the reviewer's no, the floor, the lanes, a yes too thin to be a division — leaves the worker able to hand out what it finds once it has opened the material. rerenderSystemLocked is one function now for the three ways a running agent's config moves: the clock going stale, a conversation anchoring to a project, and this. Tests: the real /task door with a stub provider, asserting the tool names the wire carried on the first request and the running worker's own belt and instructions after the refusal; the control, where the judge says no and neither gains anything; and a law that the arming word has three writers and no fourth. The wide-task test that asserted the word stayed empty was asserting the defect, and now reads the judge's own word. Closes Agent-Field#958 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the entry for Agent-Field#958 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…he winning arm (Agent-Field#990) * Revert "lane: a running stream teaches the ledger mid-stream (Agent-Field#964)" This reverts commit 75af6ee. * docs: the change entry for the revert of Agent-Field#964 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…way net (Agent-Field#923) * The turn decides, informed; promotion inherits; the ceiling is a runaway net A one-line read-only design question read home-panel files for ten rounds in 48 seconds and was taken away from the conversation that was answering it. The round-10 ceiling fired, a summary reader said `split`, and a cold worker opened on a brief plus stub pointers: its first six calls re-read the chat's own results, then fourteen more files, 551k input tokens at 24% cached over 393 seconds, and it never ticked an item. Three things were wrong at once. The decision was made by the wrong party — a reader of a summary rather than the model holding the context. It was made on the wrong signal — a count of rounds, which measures nothing about whether the work is going anywhere. And the move threw away everything the turn had read. So the count no longer moves anything, and what it buys instead is a sentence. THE TURN DECIDES, INFORMED. The rungs below the last one call nobody and move nothing. They put one note into the running turn at its next step, through the one ambient door a loop nudge already uses: the facts it cannot see about itself (rounds so far, distinct files read, bytes of results held) and the three roads on, in plain words — answer now; carry the rest on in a room with `quick_task` and `inherit`; hand out what it has not read. The cost is stated once, where the choice is: a worker that does not inherit opens on a brief about your work instead of on your work, and reads it all again. No timer, no model call, no message[0]. PROMOTION INHERITS. `quick_task` gains `inherit`: the worker is a read-only fork of the caller's transcript, so its first request carries the caller's messages and tool results verbatim and it reads nothing twice. It is bounded by a property rather than a number — refused, in a result the model reads, when the caller's context does not fit the worker model's own working room (`compactThresholdOf`, the build's own line for how far a conversation may grow), and the refusal names the road still open. THE RUNAWAY NET. `readMark` survives as the last rung only, and it no longer asks about rounds: it fires when the turn's context has passed the room it can still work in, when the loop detector has already nudged twice, or when the wall has run out. Each of those is a fact the build already had. A turn reading ten files in 48 seconds reaches none of them. AND THE CARRY-ON ROAD PROMOTES. When the net does fire, the carry-on goes through the same admission door as the tool, with the drawn items as its checklist and the context inherited. The brief road survives only where inheritance cannot go — the rung that fired because the context is too big to carry — and there the brief now carries the compiled results themselves rather than pointers at calls the worker would have to run again. Deleted with it: `checkpointSplitNote` and the `split` decision, the seam mark, `quickFromDrawing`'s bare-spec path, and the stub-pointer section for an inherited worker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The late-drawing fixture buys its reading at the net, not at the first mark Agent-Field#962's fixture holds a drawing past the turn's last step, and it opened that window by crossing the FIRST mark. With the rungs below the last one buying nothing, the first mark asks nobody, so the fixture now takes the turn to THE RUNAWAY NET instead: every scripted round reports a fuller window ([checkpointFillAt]) until the context bound fires, and the note rungs' own rows are dropped from what it returns, because a row that cost no call is not a row about a drawing landing late. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * manual: the page about a brief that could not be written carries the asker's words in its heading The probe "the run said the brief could not be written, what happened" reached adaptive-runs in the last of four slots on dev and lost that slot once this change's task pages said more about briefs. Retrieval is the feature, so the heading now says it the way a person asks it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…Field#935) * The person's word wins at the request, never at the next turn A model a person names while work is running used to land at the next TURN. For a conversation that is seconds; for a task step it is up to twenty minutes. On 2026-09-11 a step sat thirteen minutes into a wait, the owner picked another model and typed continue, the room answered `its next turn takes it`, and the step was still talking to the model they had moved off a minute later. The pick now reaches the work at the next REQUEST, within lane.SpokenWithin, through one door: - activeGeneration carries the turn's own partial buffer, so `productive()` — has this request produced anything a person could use — is a state read of the text already on their screen rather than a second count of the same deltas. - Agent.hearModelLocked is the one place a person's model reaches running work: it records the word for the boundary and, when the request has produced nothing, cuts it through cutGenerationLocked with a third cause, errPersonCut. It answers ModelLandsNow or ModelLandsNextRequest. - runTurn re-reads the word at ONE site, the top of the request ladder, and starts the chain again from the model they named. freshModel is now the one place a model gets a whole budget of its own; the rescue hop calls it too. - The room says which of the two happened — `switching now` or `the next request takes it` — and never the word "turn". RetargetTask carries the landing, over the wire as well. generation_law_test.go fails the build on a second place that cancels a generation. The manual's five claims about "the task's next turn" are replaced by what is true, and models-and-cost.md gains the section somebody asks for when they press a model mid-reply. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * docs: the change entry for Agent-Field#935 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * The beat law follows the door to the function it hands to SetModel is one line now — the work and the answer to when the pick lands live in setModel beside it — and the law that says a picked model reaches the lane beat was reading the door's own body. It reads the road the pick takes, and still cannot be satisfied by a door that does nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * The model-latch fixture pins the arm that is still true TestSetModelAppliesFromTheNextTurn asserted the contract this change replaces — a swap landing at the next TURN — so it was the defect written down as a test. What is still true from that seat is the case with nothing in flight to let go of: a word said while a tool is running is cut from nothing and rides the very next request. personsword_test.go holds the other two arms. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * The person's word is the head of every chain A failing step walked its own fallback ladder past a model the person had just named, and a step whose completer offers no chain ended the turn on "there is nowhere else to try" with their choice unasked. The move takes the word where the move is really made, so the line a person reads names the model their reply actually went to rather than a rung the boundary was about to overrule. takeTheModel is the one place a step changes model, and `root` — whose chain this is, a fact about the move and not about who made it — is the only thing that differs between the two roads. The reading of whether a step can move at all PEEKS at the word, because it runs on every failure including the ones that ask the same model again. Three stale comments go with it: SetReasoning claiming a level latches "exactly as the model does" when the two rules are now deliberately different, auxiliary.go's errand floor, and completeWithRetry's "2s, 4s, 8s, max 3 retries" — budgets deleted before the recovery wave. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * Agent-Field#925's two conversation sentences are false now, so they go The rebase carried Agent-Field#925's words onto a tree where the cut makes them untrue. `a pick in a conversation you are sitting in front of still lands on your next message` and `a model you pick with /model does not redirect a rescue that is already happening` were both true on the day they were written and neither survives the request boundary: a pick lands on the next REQUEST, and a person's word is the head of the chain. The room's own sentence loses its rescue clause with them. It was worth a clause while the pick had to wait for a move somebody else made; now the next request carries the pick whether that request is a rescue, a retry or the step's own next step, so naming the rescue would name one road out of three. Agent-Field#925's `TaskNode.picked` is untouched. It owns where a node's NEXT WORKER is built and this owns the request already out — two scopes, no second mechanism. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * One reading of what the person has read, and one door for every word Four things the review found, and all four are the same shape: a rule stated in one place and answered in two. ONE READING. `has anything reached the person` had two answers five lines apart in the same stream observer. The recall's gate counted a reasoning delta; the person's word did not, and said so on the page — `thinking where nobody can read`, which the code contradicts, because visible thinking is drawn and Agent-Field#760 made a reasoning-only turn something somebody watches. `reachedThePerson` is the one reading now: a word of the answer, a word of visible thinking, or a tool row formed far enough to be spoken. `recallAside.token` is deleted and the aside reads the turn's own. A person's word can no longer let go of a request that has drawn anything at all, which is also what closes the withdrawal gap: the state where a cut takes a thought off somebody's screen is unreachable rather than handled. ONE DOOR FOR EVERY WORD. `continue` typed into a room was enqueued and never heard — drained when the request it interrupted ended, which on the owner's own step was thirteen minutes later. That is the other half of the 14:40:10 evidence and the report claimed it was already done. A direction goes through the same hearing door the pick does. The CAUSE is the caller's, and it is the one thing that genuinely differs: a model changes what the next REQUEST rides, so it is answered at the request boundary; words change what the next STEP carries, so a direction takes the conversation's own `errSteerCut` and returns to the boundary where queued lines are drained. THE ROOM IS TOLD. The cut sends `EventRetrying` with `Next` naming the model they chose — the one door that already means `this attempt is void` — so the wait a person spoke to end stops counting. And the waiting line no longer says `trying again` when the news is a move: the row it is composed from says `moving to <model>`, and somebody who picked a model should not be told their choice was a failure being recovered from. A rescue hop's status line agrees with its own row now for the same reason. THE LAW FOLLOWS THE VALUE. The one-door test matched three tokens, so a local named `generation` — which `completeWithRetryReasoning` already binds — walked past it. It enumerates every road that hands out a generation and flags anything reached by one, however it is named. And the door compared a pick against the SESSION's model rather than the one a rescued step is riding, which cost a whole cut request when somebody picked the fallback the step was already on. `Agent.riding` publishes what the ladder always knew. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The person's word is not a boundary cut, and the one door holds both Agent-Field#962 landed mid-review with `boundaryCut`: a cut whose REASON rides no transcript is owed rather than dropped, and `beginGeneration` spends it. The rebase composes cleanly because both changes are about the same door — Agent-Field#962's owed-or-dropped decision lives in `cutGenerationLocked`, which this lane had already made the single cancel site, and `beginGeneration` spends the owed cut THROUGH that door rather than reaching for the handle it is holding. Neither of this lane's causes is a boundary cut, and the test Agent-Field#962 states is what says so. `errPersonCut`'s reason is written to `Agent.spokenModel` before the cut is raised and taken from there at the request boundary; a direction is on the worker's queue before its cut. Both ride something the next request reads either way, exactly as a recall's block rides the transcript — so a word arriving between two requests needs no cut at all, and owing one would cancel a request that was about to be right. And this cause has a second reason of its own: an owed cut reports itself answered, and that answer is what the room says out loud. A person would read `switching now` over a pick that is in fact riding the next request. The one-door law was re-run against Agent-Field#962's new spend site and catches the shortcut Agent-Field#962's own doc warns about: `active.cancel(owed.cause)` inside `beginGeneration` fails it by name and line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Three from the review: the shared reading is safe, withdrawn, and on a page (a) `recallAside.reached` replaced an atomic.Bool with a plain pointer written by the turn's goroutine and read by the sidecar's — a race whether or not anybody ever observed it. It is an `atomic.Pointer` now, and a nil load is simply a reading not handed over yet, which `reachedThePerson.did` already answers as "nothing has reached them" — the safe answer and the one that was true at that instant. Proved under `-race` over the recall, memory and person's-word fixtures. (b) `StreamReplaced` reset the four buffers and not the reading. What the dead machine drew is withdrawn on the event it sends, so the person has none of it in front of them — and a reading left standing would tell every door that may re-ask the request that they still do. (c) `let go of because you chose another model` is a string a person meets when they read a long step back, so models-and-cost.md has a section for it beside the other log-row questions: it is not a failure, here is why it is written down anyway, and it carries no door, so nothing reading the log to ask "did this turn end" counts their own act. A new heading rather than prose added to an existing one — the held-out score goes from `first 10/22` to `first 12/22` and holds top-4 at 18. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: a word said between two requests is not owed a cut The next request already carries the model the person named, so cutGeneration must answer false when nothing is running; otherwise the room says "switching now" for a request that is not starting. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…(review needed) (Agent-Field#992) * permissions: the frame names its way out wherever the pointer stands Agent-Field#946's frame and Agent-Field#985's grading landed within a day of each other and disagreed about one row. Agent-Field#946 was cut before the gate graded, so it drew `safe answer` on `deny all` only while the pointer was ON `deny all` — the same sentence then, because Agent-Field#933 opened every permission on the refusal. Agent-Field#985 made an ordinary call open on `allow all`, and the mark went missing from exactly the frames where the pointer stands on the act and the way out most needs naming. A panel of ONE never lost it: questionPanelOption marks any hands-only answer that loses nothing, whatever the pointer is doing. `deny all` is the answer that loses nothing by construction — the frame forms only where every member has one, and the row sends each question its own — so it now says so on every frame, which is one rule with the panel's rather than a second one. TestPermissionsFromOneStepAreOneFrame was the other half, and the red on dev: it read a costly set as opening on `deny all`, which was Agent-Field#933's rule and is no longer anyone's. It now asserts the pointer the grading puts there and, separately, that the refusal is named though the pointer is not on it. The manual's grouped-frame section, the gallery caption and the e2e needle's reason all still explained the deny-first pointer; each now says what is true and what expired with the grading. internal/e2e's live assertion is unchanged and was the corroboration: it waits for `safe answer` on four ordinary reads, so it would have gone red on the next live run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * permissions: one predicate decides the safe answer, on a panel and on a frame From the architecture review of Agent-Field#992. The first fix marked `deny all` unconditionally, which was a second spelling of a rule questionpanel.go already owned — and a wrong one: a frame whose member carries its asker's pick, or whose calls are plainly reversible, marked a row that its own tabs leave bare, so `2 one by one` contradicted the frame it was pressed from. questionMarksSafe is now the one predicate, questionSetMarksSafe folds it over a set exactly as questionGroupStart folds the pointer's rule, and the word is read only through questionSafeAside. TestTheSafeAnswerIsMarkedByOnePredicate fails any file that spells questionSafeWord for itself, so a third drawing of a question cannot invent a third rule about when a person is told where their way out is. The frame test pinned the mark with a frame-wide substring, which passed just as happily with the mark moved onto `allow all` — the one reading that tells a person their keystroke loses nothing when it grants four calls. It is a row assertion now, through questionRowSaying, and it checks `allow all` does NOT wear it. The `wary` case asserts the opposite of what it did, and says why. Nothing checked a FRAME's pointer against the gate's own grade — the live needle for that screen is the mark, which is now deliberately pointer-independent. TestTheFrameOpensWhereTheEngineGradedTheCalls does, with no model: the grave control is read from internal/session/testdata/consentask-rm-rf.json and must refuse to join a set, and the ordinary answers are session.AnswerOptions' own. The manual said `enter` on an untouched permission denies, in two places, which Agent-Field#953 made false. Both now split the MARK from the POINTER, and what `safe answer` means gets its own heading in the asker's words rather than a clause inside the grave case — it is drawn on every approval. The frame section lost the paragraph that split its answer list and gained a heading of its own, and the phone-width claim is scoped: under sixty columns there is no frame and no mark at all. The lifetime row's "THIS TEST FAILS THE DAY THE GRADING LANDS (Agent-Field#953)" is rewritten wherever it appears: the grading landed, nothing went red, and whether the row is owed is issue Agent-Field#995. DESIGN.md's pointer bullet carried the pre-grading rule and now carries the stakes rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ield#1001) The sentence told a person to run `aforge engine --stop` with no --workspace. That flag resolves to the HOME directory, never to the workspace being complained about, so copying the line exactly as written from inside a checkout stopped the healthy home engine and left the offending one running — and the line came back on the next launch, forever. Measured on the owner's laptop before the fix: a host on wire 14, started 2026-09-11 11:23 from a dirty build, still holding the aforge-v2 workspace twenty-two hours and eight rebuilds later. Every launch in that checkout read the refusal, and every remedy typed from it stopped the wrong host. `aforge engine --stop --workspace <the checkout>` retired it at once. The workspace comes from the host's OWN answer, remote.HostSelf.Workspace, rather than from what this process thinks it opened: the sentence is about the machine that will not let go, so the words a person types have to name what IT is holding. A host too old to fill the field keeps the bare command rather than being given an invented path. sessionHeldElsewhereSentence in chatv3.go already spells the flag for this exact reason, and its comment names this function as its voice. The voice was the one place not doing it. The version-mismatch branch is untouched. Refusing to splice a surface onto a host whose frames it cannot read is right, and the gentler busyEngineHostSentence road cannot honestly be offered across incompatible wires. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…nd two orphan packages (Agent-Field#991) * ignore macOS Finder litter The tracked Finder metadata was accidental repository noise. Remove it and teach the ignore file not to admit another copy. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * retire private planning dumps Move the lasting routing and harness research into the documentation tree, remove superseded root planning artifacts, and keep surviving references self-contained. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * prune superseded plan documents The deleted plans describe retired branches, surfaces, or research snapshots. Keep their live contracts in the current architecture and design records. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * keep only summarized design evidence Raw experiment cells and the generated home-design export duplicated retained reports and decisions. Remove the captures while preserving their conclusions. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * make retained paths portable Machine-specific paths leaked from benchmark defaults, captured reports, and source comments. Express the same locations through home-relative or neutral placeholders without changing harness behavior. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Remove orphan voice and gate packages The voice and gate packages had no importers anywhere in the tree. Remove them, their tests, and the structural-law entries their files had occupied; git grep proved both package import paths unused before deletion. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Remove unreachable Go functions Remove 68 functions reported unreachable from every main and test by deadcode -test ./..., together with the imports and private data they stranded. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the captured frames and the benchmark defaults name nobody 169 of the retained terminal captures under docs/design/polish/frames carried a developer's home directory in visible text and inside OSC-8 hyperlink targets; the substitution is length-preserving, so every column and every escape payload is byte-identical. Four benchmark scripts defaulted to a private scratchpad that existed on one machine and no other — they default under $HOME now. A private host name, a provider's internal pod address and four person-specific comment examples go the same way. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the transcription door no longer cites a package that is gone internal/voice held v1's microphone recorder and its own transcription client, and nothing imported it any more, so it went. Four comments and one design document still described it in the present tense — MULTIMODAL.md said its machinery "is real and waits on a surface wave", and transcribe.go cited internal/voice/transcriber.go as the live source of the wire shape it mirrors. The shape is unchanged and transcribe_test.go is now the only thing pinning it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * two documentation lines outlived what they pointed at JOURNEY.md's catalog used to be an index of scripts as well as a catalog of journeys; the harness that made it one drove the retired v1/v2 surfaces and went with them, so the page now says that internal/e2e covers selected v3 scenarios rather than one script per row. FIDELITY.md spoke of what "the .dc.html actually sets" after that export was removed; it is the record of what the design set. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the change entry for the second public cleanup Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the last personal paths and the last voice reference, now that their pull requests landed Thirteen pull requests merged into dev while this branch was being built, which freed six files the collision rule had put out of reach. internal/provider/ attribution.go still said internal/voice reaches the transcription endpoint on its own; internal/manual/chat/commands.md taught the slash rules with a real person's home in the example, and so did internal/tui3/detach.go and slashchip.go; docs/design/questions/DESIGN.md linked two ideation drafts that never existed in this tree; and two conversation-runtime records and one ab-routing ledger carried absolute paths from the machine that made them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the change entry follows the files that came back into reach Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
… has closed (review needed) (Agent-Field#997) * tests: the reading beside a turn stops writing into a conversation that has closed `internal/session`'s load-dependent reds name a different test each full run (Agent-Field#959). One of them is now held still: five thousand runs of `TestAPickTakenByTheClockReadsAsProvisionalAndRunsWithNobodyParked` on the Spark under load failed thirteen times, every one of them as `TempDir RemoveAll cleanup: directory not empty` rather than on an assertion, and the file left behind in the directory each time was `told.json` — the delta stamp. The writer is `Agent.refreshElsewhere`, started from the turn loop as a bare `go` of its own. Nothing joins it and `Agent.Close` does not wait for it, so it stamps the conversation's folder after the session has closed — in a test, into a `t.TempDir()` that is being removed, which reds whichever test happens to own that directory. Two changes, one cause. The reading goes through `readBeside`, the one door for a reading beside the work (sidecar.go exists because four of these each had their own idea of cancellation; this was a fifth with none). And the stamp is written in the same locked step as the assignment, refused when the session has closed — the ask lane's own law about a clock that ran out after the door shut, said about a reading. That also makes the stamp true: it claims this session's model was told, and a stamp that advanced on a block no model ever read is a day of other windows' landings this conversation never mentions again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changelog: the reading beside a turn and the stamp it writes (Agent-Field#997) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * review: the stamp is owed behind the path, the reading obeys its context, and the law reads the tree Three blocking findings from the architecture review of Agent-Field#997. The stamp was written under `a.mu` — a stat, a marshal and a file write inside the lock a steer, a cut, a named interruption and every drain take before a request leaves. That is the shape Agent-Field#876 lifted out of the meta stamp, and the ≤50 ms law cannot see it because `paceAgent` never sets `Place.Dir`. It is owed under the lock and performed behind it now, through a `stampWriter` of its own that `Agent.SettleWrites` settles: the owe is registered while the session is still open, which puts it ahead of `closed` and inside the settle `Close` already performs. The closed check moves up to the reading's first acquisition, so a closed session does not walk the index at all. The `readBeside` ask discarded its context, which left the goroutine exactly the lifetime the deleted bare `go` had while three comments and the change entry claimed it was cancelled with the turn. The context is threaded and obeyed before the walk and again before the assignment, and `tellsElsewhere` is asked at the call site so a task node's turn enrols no no-op reading in the watch. The test pinned the early return rather than the shape. `Owe` starts its performer at once, so "the file is not there yet" is a race with that goroutine and cannot be a fixture: where the call SITS is the property, and taskdelta_law_test.go reads the tree for it, with both the shape it refuses and the shape it asks for planted. The runtime half now holds the reading on a channel through a real `Close` and settles before asserting the negative. Also: `NoteTold` only moves forward, because two readings written behind the path can land out of order; and the entry no longer claims the stamp is written where what it claims becomes true — delivery is at the drain's `landVolatileLocked` and `elsewhereTold` is never persisted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * tests: a fixture that owns an agent settles what its reading owed Moving the stamp behind the path moved the fixtures' obligation with it. Three hand-built agents in taskdelta_test.go call the reading directly and nothing ever closes them, so the write they owed was left to land whenever — which the proof run caught at once: 200 runs under `-race` failed as `TestAProjectWithNoOtherWindowGetsNoBlock … TempDir RemoveAll cleanup: directory not empty`, the same shape, one level down. They settle in their own cleanup now, which is the contract `Agent.Close` meets for a real session and which placemeta.go already states for every test that reads one of those files back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * review: the reading stays on the law, lands after its turn, and owes the later stamp Four findings from the confirm review. The ask was hoisted into a variable, which took `refreshElsewhere` out of the set the sidecar law watches — that set is read off the tree, and it reads only the function literal written into `readBeside`'s second argument. It is written out inline again, inside the condition rather than behind a nil. The assignment refused a reading whose turn had ended, which is not what the context is for: `elsewhereText` belongs to the conversation, not to the turn, and loop.go says in so many words that a read landing late rides the next step. Dropped, a disk slower than a short turn re-walks from the same unmoved `since` forever and delivers nothing. The context still stops the reading STARTING the walk; only `closed` stops the answer landing. The stamp's coalescing is max-wins on the instant rather than last-closure-wins. `Agent.Abandon` releases `a.mu` before it cancels, so an older reading can be owed after a newer one, and a [stampWriter] replaces its patch — the older closure would have been the survivor and would have written a stamp behind the block the model was handed. The instant is kept beside the writer under the lock and only moves forward; the patch writes what is kept. And the law accepted `NoteTold` inside ANY `Owe`, including the meta stamp's — which is off the path and also never happens, because the next meta patch replaces it. It requires the told stamp's own writer now, with that negative planted beside the other two. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * review: the closed check and the three writes it guards are one swap-shaped hold Agent-Field#999 lands `Agent.writeIfOpen`, the one door for "write nothing into a conversation that has closed", and this reading is one of its callers the moment it is on dev. So the region is shaped for that swap now: the lock, the check, the three lines it guards, the unlock, and nothing else between them — the prose moved above the hold and the comment names Agent-Field#999 as what replaces it. No behaviour changes: the check already sat immediately before the owe, with comments between. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rs turn bad (Agent-Field#1003) The lane row's default ran aforge's own chooser on every request, paying aforge's measurement budget to second-guess a router that balances well most of the time. Now auto sends the legacy preferences and lets the router route; a per-model gate counts refusals and unusable answers, and twice in a short while arms the chooser for a window. The belief ledger learns from every named lane's answers either way, so a takeover is never a cold guess. openrouter keeps its meaning as auto without the safety.
…fer (review needed) (Agent-Field#1012) * provider, cmd/aforge: the last loose locks hold their mutex from a defer The provider half of the lockdefer burn (Agent-Field#431): forty-seven sites across thirteen internal/provider files, plus the seven cmd/aforge stragglers, were the snapshot/test-and-set-then-release idiom with the Unlock on the success path. Each became a small method that holds the lock from a defer for its whole body and answers what the caller needs, with the slow or re-entrant tail left outside. No logic, ordering, or under-lock field access changed. That was the last entry on the known-red ledger, so the ledger burns to zero here: .github/known-red.txt and its ratchet test are deleted together, as the ruling in docs/rules/ci.md prescribes. The shared repositoryRoot helper moves to internal/ci/root.go so the remaining ci tests keep their door. TestEveryLockInTheGuardedTreeUnlocksFromADefer now passes on a clean tree, and the full internal/provider, cmd/aforge, internal/guard and internal/ci suites are green. Co-Authored-By: Claude <noreply@anthropic.com> * changelog: the lockdefer burn entry for Agent-Field#1012 * docs, ci: the words stop describing the known-red ratchet that is gone The burn deleted .github/known-red.txt and its internal/ci ratchet, but docs/rules/ci.md, the Makefile header, the ci.yml laws comment and a clause in internal/remote/ratchet_test.go still narrated the ratchet as live machinery — a constant that no longer compiles. Each now says the ledger burned to zero in Agent-Field#1012, that an absent ledger skips nothing, and that the one reading stays so a ledger cannot quietly return. Comment and prose only; no behavior. Co-Authored-By: Claude <noreply@anthropic.com> * provider: the routefirst takeover drain holds its mutex from a defer e61f57a (Agent-Field#1003) landed on dev after this branch was cut, with one snapshot-then-release site in routefirst.go's tellTakeover. It became takeParkedTakeovers, the same drain-in-one-locked-step shape as its siblings, so the Emits run outside the lock and the rebased tree keeps the guard scan at zero. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…, billed arms, cache pin, shaped gate, stale-build sweep (Agent-Field#1015) * checkpoint: the race's tightening never stands the first mark below half the price A raced both-yes pulled the first [taking stock] down to the very boundary the verdict landed on, and a measured planning turn was told at round three over one issue and two listings — noise the model waved past, which is what the round-twenty note then inherited. The first rung now never stands below checkpointFirstRungFloor, derived as checkpointPrice / checkpointRatio: triage may make the first look sooner, it may not make it empty. An unraced turn's ladder is byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * journal: billed arms leave their own call lines, and a turn that hopped seals one usage line per model The measured planning chat's journal summed to $0.789 of a $1.412 bill: hedge arms and cut retries were banked to the meter through reconciled() but wrote no call line, so exactly the expensive requests left no evidence. A billed receipt now writes one, marked arm: hedge or arm: reconciled — evidence like every call line, moving no total. And the turn's usage seal named the model latched at the seal, so the mid-session hop attributed all 31 requests (2.4M input) to the second model though the first served thirteen. addUsage now keeps the turn's share per answering model — the same name the bank row carries — and appendUsage seals one line per model when there were several, the turn's one wall time riding the first by name so a replay never reads it twice. Co-Authored-By: Kimi K3 <noreply@moonshot.ai> * changelog: 1007 title under the one-line bound Co-Authored-By: Kimi K3 <noreply@moonshot.ai> * turn fold: slices of a repeatedly read file point at the file, and the newest stays whole The measured planning chat read checkpoint.go in ten overlapping slices and carried all ten, verbatim, through twenty requests: the fold bounded generic tool-result accumulation but had no notion that slices of one file are re-readable where they came from. When the foldable region now holds several reads of one path, each older slice becomes a pointer in the stub family the prompt already teaches — the read recipe, offset and limit, that brings the slice back — no copy is filed, and the newest slice is kept whole. Selection counts a kept slice as buying nothing, so a pass still runs only when it can buy the whole headroom. The trigger, target, batch-completeness and frozen-horizon laws are untouched; bash and every other tool's results keep the filed pointer they always got. Freshness of a kept slice is the held-read seam's question, not this pass's: a pointer says the range was read and how to read it back, never that the file still says it. Co-Authored-By: Kimi K3 <noreply@moonshot.ai> * session: a read the conversation already holds answers with a pointer Held-range ledger (heldreads.go): a `read` fully covered by bytes the live transcript still carries, against an unchanged file stamp, is answered with a one-line pointer instead of a fresh fetch; a changed stamp retires the whole entry, a partial overlap fetches whole, and a stubbed or folded result drops out of coverage by itself. The read tool's description prices the round trip it costs, the system prompt teaches the pointer sentence beside the stub pointer, and the chat manual quotes the behavior. Co-Authored-By: Claude <noreply> * lanes: the cache pin joins the lane chooser's enforced set rather than being dropped by it * provider: the OpenRouter-takeover gate counts a refusal only when the router's own pick was refused A narrowed demand's refusal is evidence about our choice, not the router's default: for the gate to count it arming the takeover from within the takeover's own demands. shape reaches the door from the one classifier that holds the knobs (refusalobject.go's Client.refusalObject), and the refusal door asks it (routefirst.go's Client.noteRouterRefusal, velocity.go's two refuseLane branches). The answer sides stay shape-agnostic: an answer that arrived is a verdict about the machine that spoke it, whichever spine chose it. Measured in a live chat (2026-09-12): takeover armed, every narrowed demand 404'd, each 404 re-armed the gate — four 'Retry 1/2: relaxed the endpoint filter' lines at ~80k tokens a re-send before the first rung went bare. * tui3, session: a launch sweep names every live session on an older build rev The third binary-shadow incident in the repo's history ends with a visible warning instead of 'same old rev' on every screen. The sweep reads presence files (fail-open), freshness from presenceWindow (age, never pid — the file's own law), and the launch gate emits one advisory line through the same noteFacts door the landing keys use. Manual section added to starting-aforge.md. * checkpoint: a probe pins the first-rung floor against race-at-any-round * changelog: entries renumbered to the pull request they ship with * fmt: sweep and law-visit edits through gofmt * tests: pin the hop's split seal instead of the old one-line shape TestEveryResponseWritesItsOwnLineWithItsOwnShape names two distinct answering models in its fixture (the first response falls back to the latch, the second names vendor/served-model), so the per-model seal split correctly writes two usage lines there. The expectation now pins the split — one line per answering model, figures per model, the wall time on the first by name — exactly the hop case usagejournal_test.go covers. Co-Authored-By: Kimi K3 <noreply@moonshot.ai> * provider: the gate's shape test is a demand, not the ladder's membership The first cut classified shape through wirePreferences(...).membershipNarrowing() — the ladder's first-rung question, which counts require_parameters as membership. Every machine-unmodified ask read as narrowed, so an ordinary paced refusal (one of the router's own picks queueing) stopped arming the takeover: gate_e2e_test's TestTwoPacedAnswersHandTheRoadToTheChooser went red. Shape is now read from the knobs as a DEMAND — hedgeLane, or a lane choice carrying admitted names — with require_parameters and the ledger's own Ignore vetoes left outside the gate's question. * session: restore the offset/limit pin sentence and route held-reads through the one decode door lawregistry_test.go pins 'page the rest with offset/limit' in the read description; heldreads.go now decodes with decodeToolArguments like every other tool; the round-trip sentence is trimmed to keep the lean prefix under its budget. Co-Authored-By: Claude <noreply> * exec/bare: the edit merge sentence owns its whole rule, reclaiming the round-trip-priced read sentence's room The lean prefix was 62 bytes over on CI. The 'large unchanged regions' clause restates the merge sentence, so it goes; the held-range round trip sentence stays whole. Co-Authored-By: Claude <noreply> * changelog: 1015-stale-build-sweep surface fixed to the enum it checks --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Kimi K3 <noreply@moonshot.ai>
…-Field#1004) * e2e: a needle names a key, it never spells one TestQuestionsE2E has been 14 of 18 red since Agent-Field#933 took the brackets off every key on this surface. The suite went on waiting three minutes at a time for `[1] delete it` while the line drew `1 delete it`, and the untagged gate that exists so this cannot happen (Agent-Field#184) was green throughout, because it was looking at the half of each needle that had not moved: - nine needles in questions_e2e_test.go were inline literals, which the table's gate cannot see at all; and - eleven rows of the table spelled `[c] change` in `screen` while their `source` said only `change`, so the gate checked the word and never the key in front of it. So a row that is offered on a key now NAMES the key, and one function puts the two together: - tuiWord gains `key`, and [say] returns [tuiWord.spelling] — the word alone on a plain row, `keyedWord(key, word)` on a keyed one. - [keyedWord] is the one place this suite writes the gap between a key and its word. The nine pasted answers in the questions scenarios go through it, so `delete it` stays the scenario's word and the `1 ` in front of it stays the product's grammar. - nineteen rows are respelled onto it: the question grammar's own keys, the consent block's two, and the four landing answers, whose one-space column internal/tui3's own relanding and papercuts tests pin (`a resolve it n drop it s tell it`). And [TestNoNeedleSpellsAKeyTheSurfaceStoppedSpelling] is the law that keeps it: a go/ast walk of every screen-reading call in this package refusing a needle-position literal that brackets a key or pastes a numbered answer onto its word. It reads the table as data and the suite as source, and it leaves every other literal alone — a sentence the MODEL wrote is a coincidence, not a source of truth, which is what the suite's own header has always said. internal/manual/chat/questions.md said a key is drawn `[1] allow once`. It is drawn `1 allow once`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the e2e question needles entry (Agent-Field#1004) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * e2e: the chip is a tail, and a letter is the question's only once you aim The first paid run after the respelling went from 4 of 18 to 7, and the two families left in it are the same rot one layer down. THE CHIP LEADS WITH THE QUESTION'S OWN HEAD. `questionChipTail` waited for `question · alt+a`; the status line draws `? delete the build directory? · alt+a` (question.go's questionSegment) and spells the word `question` only where there is no head, or `3 questions` where there are several. Its `source` was `alt+a`, so the untagged gate was green on it exactly as it was on the brackets. The row is its own name now: the tail, ` · alt+a`. A LETTER IS THE QUESTION'S ONLY ONCE YOU HAVE AIMED AT IT. `o`, `c`, `x`, `?` are each the first letter of a word people type into the box, so the block does not take one from somebody who has not yet looked at the question (questionkeys.go's questionAimKey; the manual says it in a person's own words). Six scenarios pressed `o` to open a page, the `o` went into the message box, and each waited out its three minutes for a page nobody had opened — with `› o` on the screen it printed. So [aim] is the gesture, spelled once: `↓` then `↑`, because an aim may not be an answer — `enter` takes the pick and `esc` puts the question away — and the walk is therefore walked straight back, leaving the pointer where it was and the hand on the block. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * e2e: the page opens on the pointer, so the foot says what enter would send The room scenario waited for `nothing chosen yet` on a page that had just opened on `1 postgres`. Since Agent-Field#789 every answer has a pointer the arrows walk and enter takes, and the page opens where the block's pointer stood — questionroom.go's own enter path says so — so a page with answers on it always has one to send. `nothing chosen yet` belongs to the `something else…` row, which stands after the last option and carries no key. So the moment is read the way it now happens: the foot says `answering ` what the page opened on, and it may not also claim nothing is chosen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the whole of what moved, and the three defects under it (Agent-Field#1004) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…oes, and the prefix gate weighs the real belt (review needed) (Agent-Field#996) * roles: the compaction role is deleted, because no compaction has called a model since the summariser went RoleCompaction was a priced, described, settings-visible dial wired to nothing. [Agent.compact] takes `_ context.Context` and makes no model call at all — a pass is two mechanical rearrangements of text the session already has — so the row on the Providers tab offered a person a model for a call that never happens, and TierHigh's patience was derived from a summary nobody writes. The role, its tier assignment, its description and the settings and manual text that offered it all go. The high tier keeps every tenant it actually has — the auditor, the shaper, vision, the repair, the careful part of a division — each registered from the package that makes the call. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * session: every request says what it is for, and the door is the only thing that spells it NINE OF THE ELEVEN CALLERS OF THIS PACKAGE'S MODEL DOOR REACHED THE WIRE ANONYMOUSLY. The guardian, vision, the shaper, the spell-out, the subharness intake, the run planner, the harness designer, the ceiling's handoff draft and a saved program's own AI step all called completeWithModel with no provider.WithCallTag anywhere above them, so the model-call log could not say what any of them was: 2,309 of the 2,839 untagged finishes in the ten days to 2026-09-10 are this package's, and with them the answer to "what was this build spending that model on all night". The tag was a context value a caller could set or forget, and forgetting it is silent. It is an argument now — clientdoor.go's `callPurpose` — so a call with no purpose does not compile, and the door is the one thing in the package that calls provider.WithCallTag. The three callers that did stamp their own (the turn, the ask tool, the errand ladder) pass a purpose instead, which is one spelling of one fact where there were four. AND auxiliary.go's OWN CLAIM WAS THE FALSE ONE. It said callRole was "the one door all auxiliary provider calls pass through" while ten calls went round it. It is the one door every ERRAND passes through, which is a narrower and true claim, and the sentence says so and names what is legitimately not an errand — vision streams into the room in the person's own turn, the handoff draft is billed to the turn on the turn's own model, a program's step runs on no role's model at all. nohiddenwork_test.go is the law, on the laws gate: a blank purpose fails the build, a WithCallTag outside the door fails the build, and the walk fails if it ever stops finding the door. No behaviour changes. Every call goes to the same model with the same options; what is new is that its row in the log has a name on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * tests: the prefix gate weighs the belt a configured machine actually carries THE GATE WAS POINTED AT A SHAPE NOBODY RUNS. fixedPrefixBudget's own doc comment has always said it bounds "the belt the shipping conversation door assembles". The fixture under it was v3ShapedAgent: a conversation with no memory store, no accounts hub, no standing items and no saved programs — eighteen tools, 39,073 bytes, eight kilobytes of headroom, green every day. A machine somebody has finished setting up carries twenty-three tools and weighs 53,025 bytes, which is 5,025 OVER the 48,000 cap the gate was enforcing. It has been over for as long as the shape existed and the gate could not see it, which is Agent-Field#576's shape exactly. The gate now weighs beltShapes[0] — "the shipping conversation, fully wired", the same definition prompt_belt_test.go uses, through one new helper so the two cannot drift apart again. AND THE FIGURE BECOMES A RATCHET. "The measurement plus a tenth" was right when the number came out of a diet that had just been paid for. This measurement is not the end of a diet; it is the first honest weighing of a prefix that had never been weighed, already past what the last diet aimed at, so a tenth on top would be five more kilobytes nobody chose. It is the measurement and nothing else, and anything that grows the shipped prefix now fails the build. WHAT IS OWED IS FILED, NOT FIXED. 48,000 stays as the stated target and the test prints the 5,025 shortfall on every green run. The bill is one tool: `stand` is 9,607 bytes, more than a quarter of the whole tool block and nearly twice the next heaviest. Trimming a schema is a change to what the model is told, not to a byte count, so it belongs to whoever owns the standing belt rather than here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the auxiliary inventory entry (Agent-Field#996) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * replay: the tag law reads the door, because the door is where a tag is stated now TestEveryTagTheBuildWritesResolvesToARoleSomebodyDeclared walks the tree for provider.WithCallTag. internal/session has exactly one of those now — the relay line inside the door — so the law was reading a variable it could not resolve and finding fourteen tags for a table of thirty-seven. It reads the door's own call sites instead, which is the same thing the build does: the purpose argument is what reaches calllog.Record.Tag. The `callPurpose(...)` conversion comes off before the argument is read, a role worn as a purpose resolves to internal/roles' vocabulary (over-approximated, because this law is safe answering with more tags than one site writes and holed answering with fewer), and the door's own constants are read from their declaration the way roleWords already reads internal/roles. AND IT IMMEDIATELY FOUND THE TWO CALLS THAT HAD JUST BEEN GIVEN NAMES. The ceiling's handoff draft and a saved program's AI step now write tags, and nothing priced them: both are lane.RoleAuxiliary and both have a row. The draft rung is the dearest side-call on the ceiling road and it has been invisible to every reading of calls.jsonl until now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * manual: the roles table stops listing a role the binary no longer registers The models-and-cost page's roles table is described on the page itself as 'built from what is registered in the running binary, so it is the truth about this build'. It listed `compaction`, which nothing registers any more, and the crew's careful line and its account of what aforge calls on your behalf both named the summary a compaction keeps — a call that has not existed since the summariser was deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix gate: the budget is the widest machine's, not the one it was written on The first spelling of the ratchet was 53,100 — the laptop that weighed it said 53,025 — and it failed on the runner that proved it, at 53,132. The prefix is not the same size everywhere: `grep` says a longer sentence about itself where ripgrep is absent, which is 134 bytes on every request of every turn. So the gate weighs what the WIDEST machine pays. bare.WidestGrepDescription is the one place that knows which of the two sentences that is, and widestBelt swaps it in wherever the gate runs, with a law that fails if the tool it names ever leaves the belt — otherwise the budget would quietly get easier. The residual is the shelf: load_capability lists the groups THIS BUILD has, 27 bytes more on a machine that can edit video. That is filed in the file's head rather than fixed here, because naming what a build COULD have is a change to what the model is told. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the prefix figure is the widest machine's Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: a role that stops existing is dropped from the profiles that pin it Deleting RoleCompaction left the word in every config.json that had pinned it, and the panel re-serialises the whole `models.roles` string on any change — so the next time that person moved ANY OTHER pin the write came back `"compaction" is not a role`, and every role pin on the machine was unchangeable until somebody hand-edited config.json. The deletion had no reading for what it deleted. roles.Retired is that reading: a one-way list of the words this build used to answer to, with the line that says what happened to each. It is the only memory the build has of them, and without it a dead word is indistinguishable from a typo. ParseModelRoles drops those keys and says so once per process; writeModelRoles takes them out of the TEXT, which is what is actually stored, so a person who changes one pin stops re-saving a sentence about nothing. The test is the exact string a pre-deletion profile holds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prose: nothing says a compaction asks a model any more A compaction is two mechanical passes over the transcript; it has never asked a model. Six comments and two manual lines still offered it as the example of a billed auxiliary errand — the pocket the title comes out of, the thing the careful tier is for, a non-streamed call like a harness node — which is a sentence about a call that does not exist, and was the figure the careful tier's own patience was derived from until this PR re-derived it. The settings hint for `careful work` no longer promises it either: what that tier actually buys is the check on finished task work, the brief a task is shaped into, and reading an image. The transcript NOTE a compaction writes is still called a summary in agent.go, because that one is real. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: a role's word lives in internal/roles, and a law says so `const spellOutRole roles.Role = "spellout"` lived in internal/session. It registered, resolved and tagged its call correctly — and reached the cost report as a word nobody had written down, because roleWords parses internal/roles and nothing else. roleOf prices an unrecognised tag as a background errand with nobody waiting, so the ONE auxiliary a person sits and watches was the one counted as if it did not matter. Nothing failed; a number was quietly wrong. The word moves to roles.RoleSpellOut beside its siblings, the Register call stays at the call site, and TestEveryRoleWordIsDeclaredWhereTheVocabularyIs fails the next one. And the replay walker stops enumerating receiver spellings. callName flattened one selector level, so three of the six rows in that switch — `p.agent.completeWithModel` and friends — rendered as "" and could never match: the ladder looked complete and was half dead. methodName asks the only question the law has, which is the method's own name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix gate: both arms weigh the shipped shape, at the widest machine THE LEAN ARM HAD THE SAME HOLE THE FULL ARM WAS REPAIRED FOR. leanShapedAgent built its own thin config — no memory store, no accounts hub, no standing items, no saved programs — so the arm that bounds the prefix for the person with the LEAST room weighed a belt without `stand` (9.6 KB on its own), `remember` or `search_conversations`, none of which leanCapabilityGroups shelves. It is the shipped shape on a small window now, which is what its own comment always claimed. And three ways the number could go back to depending on who ran it: beltShapes[0] read the fullest shape only until somebody put a row in front of it. beltShapeNamed asks for it by name. WidestGrepDescription returned the fallback sentence because that one is longer today; it now measures both and returns the longer, and widestBelt ASSIGNS rather than comparing — a swap that only fires when it makes the number bigger is a swap that stops firing silently. load_capability names the groups this BUILD has, and `edit_video` exists only where ffmpeg is on PATH — 27 bytes of prefix that depend on a program nobody installed on purpose. loadCapabilityDescription takes the members as a question now, so the gate can ask for the widest answer instead of this machine's. Both budget figures are re-measured in the next commit, on the Spark. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: both caps are the measurement, and the three own-client roads say what they are THE CAPS. Full 53,141 and lean 44,989, both weighed on the Spark against the shipped shape at the widest machine, both with no headroom, both printing the shortfall against the target they owe on every green run. PERF.md moves in this commit, which is the rule for a cap. THE ROADS. memory_consolidate.go, standing_run.go and tools_doc.go each build a provider client the one door does not make — a longer timeout, static routing, a document config — and complete on it directly. That is a real difference, so the answer is not to force them through the door; it is to make them say the word the door says. clientdoor.go's withPurpose is that, and it is still the only file in internal/session that spells provider.WithCallTag. The two errands this build runs most often with nobody there reached the call log with NO TAG AT ALL, which made them indistinguishable from a turn that had lost its name. The standing check is `standing-check` and not `sentinel`, because cmd/aforge already writes that word for the resident's quorum errand and two calls under one tag is a reading of neither. The law now pairs the halves: a file that builds its own client owes a withPurpose, and it fails if it finds fewer than three such files — a structural law that matched nothing would pass for ever. And `compaction` comes out of the replay role table: no build can write it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the four findings the review turned up Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * law: the purpose is required on every own-client call, not once per file A file-level pairing is satisfied by one road naming itself while the road beside it stays anonymous, which is the exact shape of the failure this law exists for: the forgettable one is always the second one. Every completion in a file that builds its own provider client must now carry a withPurpose on the context it is handed — inline, or through a local the purpose was folded into. standing_run.go writes the purpose four wrappers deep and completes on `callCtx` several lines later, so the reader follows assignments to a fixed point rather than looking only at the argument. And the second pass counts the CALLS it judged, not the files: three files that build a client and nought completions in them would pass in silence. cmd/aforge-replay's two doc comments stop citing auxiliary.go's deleted WithCallTag line and point at clientdoor.go's callPurpose, which is where the tag is spelled now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: the new law found two more of its own kind, and they are fixed TestEveryRoleWordIsDeclaredWhereTheVocabularyIs caught `const standingSentinelRole roles.Role = "sentinel"` in internal/session the first time it ran, which is the second instance of exactly the defect it was written for and the reason it is a law rather than a note. The word moves to roles.RoleSentinel; the Register call stays at the call site. And with `spellout` finally visible to roleWords, the tag law asked cmd/aforge-replay to say what it prices as — so the table gains the row, which is spellout.go's own lane.RoleAuxiliary and not a second reading of it. That row carries the seam it exposes: a person SITS AND WATCHES a spell-out, and an auxiliary is by definition a call nobody's seconds are being spent on. Either the lane role or the product is wrong there. The table's job is to agree with the build, so it does, and says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: a dead pin is a dead pin, and three more numbers stop depending on the machine THE RETIRED LEDGER IS DELETED. It was a map of the words this build used to answer to, so a dropped pin could be told apart from a typo — and it could not earn its keep. Both are a pin no call will ever consult, both should stop being written back, and the only reader who can act on either is the person adding a word right now. Keeping it meant every future deletion owed it an entry, and the day somebody forgot, the old failure would come back exactly as it was. So the reading is symmetric: a pin for any word that is not a role is dropped, the writer refuses only a name being ADDED, and nothing dead is ever written back. The row DRAWS what is acted on (config.LivePinsAt) rather than the raw stored text — it used to draw `compaction: some/model` as a live pin while the list under it had no such line — and the panel says "no longer a role — that pin is ignored" to the person about to lose it. It is a sentence and not the log.Printf this had, which was the only one in internal/config and landed on stderr in every headless and --json door. AND THREE MORE MACHINE-DEPENDENT NUMBERS. The lean page interpolates the working directory, so that arm measured 45,034 on macOS against 44,989 on Linux and failed — a fixture artefact worth tens of bytes in the gate whose entire purpose is to be one number for everyone. The lean arm was also being handed the FULL shape's load_capability sentence, making its figure a hybrid of two belts that neither pays. And the replay table priced `vision` as an errand nobody waits on while image.go, its only writer, sets lane.RoleTalk with the reasoning beside it: a look at an image streams into the room during the person's own turn. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: one weighing, one shipped shape, and a debt that is enforced THE DEBT WAS INVISIBLE. It was a t.Logf, and nothing in the Makefile passes -v — so the one line saying the shipped prefix is thousands of bytes over what it is supposed to be was printed where no human and no CI log would show it. The cap is the TARGET plus a dated waiver now, one per arm in one place, and a waiver only ever shrinks: known-red's discipline applied to bytes. Growing the prefix takes a diff with somebody's name on it. ONE WEIGHING. The two arms were forty lines each, written twice, and the copies had already drifted — only one printed its shortfall, and it was the arm with the smaller debt. reportPrefix is called twice. ONE SHIPPED SHAPE. v3ShapedAgent WAS the second opinion: its own thin config, eighteen tools, weighed by four gates including both budgets. It is shippedShapeAgent now. beltShapes' lean row built a third config again, so the belt law and the prefix gate were measuring different lean conversations under one name; both call buildShippedConversation. ONE VOCABULARY READER. purposeWords and roleWords were the same function with a different path; they are constWordsOfType, read once, with the empty-result panic inside it. The role law catches the CONVERSION spelling too — `roleRepair = roles.Role("repair")` was invisible to it — and now also reads every roles.Register argument, which is the spelling that cannot be worked around. roles.RoleRepair is declared with the others. And the manual stops teaching a summarizer rung, its `session: summarizer returned nothing` string, and a focus appended to its instructions. None of that exists: a pass stubs and folds, asks no model, and never folds your own words. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: the lean page is weighed the same on every machine, to the byte The working directory was a fixture artefact worth tens of bytes; the Workstation line is runtime.GOOS/GOARCH and worth one, which a ratchet with no headroom fails on just as hard. Both are normalised at the one place that needs them to be, and the product still tells the model the truth about the machine it is on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: the lean waiver shrinks on its first run, and `repair` gets a price The lean figure went 44,989 → 44,920 because the page's working directory stopped being a fixture artefact and the lean arm got its OWN shelf sentence instead of the full belt's. That is sixty-nine bytes off a number that had been measured on a hybrid, and the waiver comes down with it — which is the whole behaviour the ledger exists to have. And `repair` reaches the replay table. It only became visible there when the role stopped being conjured at its call site as roles.Role("repair"): a word spelled that way is invisible to every reader of the vocabulary, which was the defect, and the law that now catches it found this the moment it could see it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the review's findings, all of them Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: the lean waiver shrinks again, to the byte the page now measures Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: the registry is the tier table, and the vocabulary is a different question A REGRESSION I INTRODUCED, CAUGHT BY THE SUITE. Making the read drop any word the REGISTRY does not know threw away `imagegen:paint/model` — a real pin doing real work. A role gets into the registry by registering, which is how it gets a tier, and a role with no tier never does: a painter is chosen by a pin or not at all, since a chat model in tiers.high is not a statement about painting. So the registry was never the answer to "what are the roles". roles.Vocabulary is that answer and roles.Known is the reader's door to it. The list is hand-written, which is a thing that falls behind, so a law parses the file it lives in and fails when a declared role is missing from it or a listed one is not declared. The refusal lists the vocabulary too, so a person is shown `imagegen` as a name they may pin. And the retired-pin test seeds the row the way a profile written before the deletion holds it — straight into the file, because the writer is exactly what would refuse it today and that person never typed it today either. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * session: the two holding actions name the issue that deletes them The `standing-check` rename and [widestBelt] are both measurements around a problem rather than fixes for it, and both are deferred to a cross-package wave rather than grown here. Each now says so where a reader meets it, and names issue Agent-Field#1010 (spine: Agent-Field#928) as the place it is deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * config: whether a pin was already there is a question about the person's file writeModelRoles forgives a retired word it FINDS and refuses one being TYPED, and it asked parseModelRoles which of the two it was looking at. That reader drops every retired word by design, so the stored row it handed back could never contain the one word the check existed to find: a name that had sat in the file since before the deletion read as a name typed for the first time, and a machine with an old `compaction:` pin could not save a change to any other pin. The set is read off the stored TEXT now — storedRoleWords — because every reader above that line drops what it does not recognise, and the dropped word is exactly the word this question is about. The asymmetry gets its own test: the same word, forgiven when found and refused when typed. The old test only ever typed a word that was never a role, so the half that broke was the half nothing watched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * session: a held-reads pointer sentence pays 150 bytes on both prefix arms (Agent-Field#1015) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…gent-Field#1018) * tui3: the draft kill ring — whole-box clears keep the words, and the ↑ walk visits them dim in front of the sent history * tui3: /drafts, the page over the kill ring (enter restores, d lets one go) * changelog: the draft-page entry uses the PR's own number * tui3: /drafts takes its place under /compact and has a fate on home
…to OpenRouter unpinned, exactly the named provider pinned — is the row this build ships (Agent-Field#1019) `simple` is the default routing row: no pin sends no provider object and OpenRouter's own routing answers; a pin sends exactly {only:[X], allow_fallbacks:false}. The routing row reaches every client this process builds; a pin is refused by the wire, not by a saved memory, and the person is told in the conversation; the pin rides the calls a person is reading and every call of a command they typed; the call log names what each attempt carried; the picker predicts no machine where nothing chooses; a stall under simple without a pin is reported, never rescued. latency, price and off remain opt-in. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
… still queued (Agent-Field#1024) The hand-over press wakes a turn that drains the steering queue and, if it finishes, hands unsettled nodes back; two tests read the queue between those two events and saw it shrink. They now count what the model was told, queued plus drained, and hold the turn open so the press under test lands while the model is still deciding. No production change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…tall (Agent-Field#1021) * docs: a README that sells the chat flow and tells the truth about install The README was an install page carrying four curl lines that 404 for anyone who is not signed in: the repository is private, `scripts/install.sh` is not on `main`, and the `agentfield.ai/get/aforge` proxy is an unmerged pull request on the website. It said nothing about the product. This one leads with what aforge is — a terminal session you talk to, that reads and edits files, runs commands, hands work to tasks you can walk away from, remembers, and takes slash commands — and shows a real captured screen of that loop on the default model. The install section puts the road that works today first (clone, `make build`, `bin/aforge`), then names both curl roads and says in one sentence each which is live and which is not. Long tails — installer flags, the slash-command table, the key table, the tool names — are folded. `internal/manual/chat/running-from-the-terminal.md` carried the same four dead curl commands, so the manual law makes it the same change. Its first section now says the same true thing; every `## ` heading is untouched, so the probe table still reaches it. Numbers appear only where a cited constant backs them, and the two places shipped text disagrees with itself (`--parallel` 8 versus 32, `--budget` 150,000 versus `--token-budget` 220,000) are left out rather than picked. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: README fixes from the refutation pass An independent lane re-ran every recipe in the claims ledger and drove the real binary in tmux. Three sentences did not survive, and one whole road was missing. The permission card was fiction. The ledger "checked" it with a grep that matched a comment at internal/tui3/consent.go:20 — whose own next paragraph says the block draws it now. What the surface actually draws is a bordered block whose header counts ten seconds (config.DefaultConsentTimeout), whose second choice is the bare word `always`, and which carries `c change`, `? ask back` and `safe answer`. Replaced with a verbatim capture at 100 columns, and `c` and `?` are now described in the words question.go uses. `aforge models` was listed as needing no key. It exits 1 with `aforge needs a model to work with.`; the repo's own manual page already said so at running-from-the-terminal.md:583. It now has its own sentence. The first-run quote was the branch nobody sees. firstrun.go:808 picks `setupConnectWord` wherever browser connect is available, so a fresh reader never meets `setupKeyWord`. Both roads are now named, folded, with the condition that chooses between them. And the gap: "run `aforge` inside a project" never said what that means. A new section gives the launch order from cmd/aforge/chatv3_layout.go:84 — `--workspace`, else the git root, else the directory, except in your home directory or under /tmp where aforge keeps a folder of its own and says so — names `/workspace` as the door, and says that on a machine with conversations on it bare `aforge` opens home rather than a chat. All of it was reproduced in tmux first. Smaller: `/spend`'s registered meaning carries its ` · alt+3` again, the nav row gains the Tools anchor, `ctrl+g` and the right-hand column are described as the code has them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: the change entry for the README rewrite (Agent-Field#1021) Five invalidations, because five things a session might remember about this repository stopped being true: the four dead curl lines as the install road, the same four in the manual page, the one-line permission card, `aforge models` as a keyless command, and `setupKeyWord` as the first-run copy. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: the account tools are named as conditional The tool-name table listed the five Gmail and calendar tools and the four Slack ones with no condition, which reads as "Gmail is on the belt". It is not: familyTools (internal/session/tools_connect.go:438) hands out the Google five only for a connected Google account and the Slack four only for Slack, and connectcaps.go:57 holds the same two sets as the inverse. The conditions paragraph under the table now says so and names the door a person uses, `/connect` (internal/tui3/commands.go:78). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…ire will ask for, a routing change lands now, the debug pin records bodies, enter unpins (Agent-Field#1025) The status chip, the settings lane row and the picker read the pin the transport will act on (provider.PinNow) instead of the profile row, so a retired pairing draws auto with its reason and never @x over a bare request. A routing change in the settings sheet re-installs the row and reaches the very next request because the profile door hands no static routing down. AFORGE_DEBUG=1 takes the in-process road like --debug and writes request bodies. In the lane fold, enter on the machine in force unpins it and typing filters that model's machines. Closes Agent-Field#1022. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…hat drew it, and the opened step shows the prompt (Agent-Field#1026) The generate_image row draws the file it is about in primary ink and the image model that actually drew as a dim qualifier, read from the tail of the tool's own result line (", generated on <model>") so the row and the request cannot disagree; an unknown model adds nothing. Opening the step leads with the prompt, one dim line per other input, then "drawn with X" or "asked for best · drawn with X", then the picture. view_image rows gain their file the same way. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…ands every engine down (Agent-Field#1000) Home's foot box is a block of one height — three rows, padded below the draft so the caret stays put — and the floor is spent only from frames that have the rows to spare, through one door the chat's foot and every place's frame ask. `aforge engine --stop-all` names each workspace it stands down. Gate re-run on Spark against dev 0738312 merge: laws, pr-ready (tui3 312 s, cmd/aforge, enginehost) all ok; driven captures at 120x40 and 80x24 match dev. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…e behind a model is provider (Agent-Field#1027) Owner ruling 2026-09-14 (Agent-Field#1023 item 1): everywhere a person reads, the thing behind a model that answers a request is a provider — the settings row, the /model hints (→ providers), the fold sentences, the rescue and stall notices, the config hints, and the manual page titled Providers. Code identifiers, config keys (lane.talk), the @morph chip and the /status --json `lane` key (a script contract) keep their spelling. A law test fails any tui3 string literal that says lane. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…nt-Field#1033) * PERF.md: the prefix budget table says the caps the gate enforces The waivers were raised by 150 on each arm in the commit that made them, with the reason in the code comment, and this table was never opened — which is the one thing the performance law forbids: a cap that changes changes the doc in the same commit. The table now reads 53,291 and 45,066, over the targets by 5,291 and 13,566. Closes Agent-Field#1030. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv * docs: change entry for Agent-Field#1033 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…when you come back to the tab (Agent-Field#1036) * session: a card for a decision you already made is not asked again when you come back to the tab A turn's backlog is every event that turn has sent, kept so a surface arriving mid-turn reads the work from its first line. A CARD in it is the one event that is not a report of something that happened but a question about something that has not — and the replay handed it over verbatim, whatever had since been decided. So a person who approved a task, looked at another tab and came back was asked to approve it again, on every return, for as long as that turn ran; and because a question takes the keyboard where it is drawn, the conversation underneath it could not be scrolled while it stood. Both symptoms, one cause. The replay now consults the answer. [eventHub.attach] is handed what is still being asked — the banked words, read off a.mu at the moment of the attach, which is where a question goes on the book when it is raised and comes off it the moment it is answered or withdrawn — and leaves out a card whose question is no longer one. The backlog stays a faithful log of the turn; what is filtered is the REPLAY. [questionAsked] names the question a card put in front of somebody, in the lanes' own keys, for consent, a task proposal, a standing card, a harness offer and a connect ask alike. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv * session, tui3: the card comes back with your answer under it, not with the question again The first half of this change left the settled card out of a turn's replay altogether, and that traded one lie for another: the surface reads a propose_task call whose card never arrived as a call that was refused (task.go's [app.refuseFormingCard]), so coming back to the tab said `not started · the call was refused` over work that was running. So the engine states the outcome instead of the replay swallowing the question. [taskWait.decided] restates the proposal with the answer stamped on it the moment anybody settles it — a person, another window, or the countdown — beside the restatement [taskWait.withdraw] already made for the other ending, and at the one place both roads pass through. A card that states its own outcome is not asking anything, so the replay keeps it and leaves the open one out. The surface draws it as what it is: the assignment with the answer under it and no question raised. [taskVerdict] is the one reading of approved-and-redirect that the window whose key answered and the window replaying a decision both take. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv * docs: the change entry for Agent-Field#1036 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…he same turn carries on (Agent-Field#1037) * approval: let account discovery reach its own question The shipped prompt blanket put approval questions in front of both account discovery and the connect card. Account listing now lifts as a read, while the connect tool lifts because its own card is the one consent question; named rules, deny, and the existing floors still win. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: carry account connections through the same turn Connect answers used to collapse refusal, silence, and typed instructions into one no, while the tool description told the model to wait for another turn. Answer provenance now survives to distinct sentences, one shared instruction says to continue on the next request of this turn, and the belt teaches the conditional discovery path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * tui3: settle browser waits when their turn ends A browser row could keep waiting and animating after its turn had closed, and words typed beneath a browser question opened a key-check card. Turn settlement now closes those rows with the existing incomplete wording, and only typed-key questions can open the check card. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: hide browser sign-in exchange details Browser callback failures used to pass their raw exchange text, including a state nonce, into the transcript and tool result. The session boundary now keeps vendor refusals in plain words and replaces internal exchange failures with one honest, non-sensitive sentence. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * manual: tell the truth about account connections The manual said the browser stayed closed, concurrent credential writers could lose a change, and account bootstrap tools followed the ordinary approval path. It now describes the opened browser and retained address, locked store, single connect question, same-turn continuation, and the distinct ways a question can finish. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: let a connect answer beat the clock The five-minute branch could call an answer silence after its resolver had already claimed the question. The clock and resolver now share one atomic winner, and a claimed answer is returned even when its send is still in flight. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * connect: hide every failed browser exchange The session hid familiar OAuth failures, but unknown text passed through and the Connections tab still drew raw callback errors. Browser failures now cross one deny-by-default boundary; only a short vendor-shaped refusal is retained. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: prove account pickup on the shipped posture The same-turn acceptance ran under blanket allow, where its zero-consent claim could not fail. It now runs under the shipped prompt posture and proves the connect card is the only question before the newly armed tool runs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * manual: keep account answers inside the search window The privacy heading traded away the old asker's words, the SearchBoth guard was rewritten into a plain search, and the MCP inventory was split under false counts. Both vocabularies now retrieve, the rescue direction is loud again, and the original 28-row section is whole. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: the account cue pays for itself out of what was said twice The new account sentence and the same-turn wording pushed both prefix arms 79 bytes over their caps, and the sentence named `services` without the belt fact claiming that name. The fact now lists both tools it spells, says only what has to be true before the call, and `use_service` no longer repeats the ordering the fact already gives — leaving both prefixes below where they were on dev. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * changelog: the connect-on-demand entry for Agent-Field#1037 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…e keystroke (Agent-Field#1039) Home's ctrl+e writes the archive flag and then re-reads the world on the spot, so that the row moves under the hand rather than on the next sweep. The seam it re-read through answers from what is held and refreshes behind itself, and the write went straight past that cache to the engine — so the rebuild redrew the row exactly as it was, and the row went only when a later beat's fetch had returned and a later beat rebuilt. Two seconds of allowed staleness plus up to two three-second beats is the several seconds a person saw between pressing the key and watching the row go. hostWorld.archive is the seam now: the write over the wire, then the held copy corrected and the entry aged out so the next reading still asks the engine what it really thinks. That is hostStanding.save's correction, which already existed for the ambient side, applied to the one write home makes against the world. A refused write changes nothing here, and bringing a row back is the same correction in the other direction. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…eld#1819) * fix: price qualified shell models on their selected service * docs: record qualified shell model pricing for Agent-Field#1819
…Agent-Field#1820) * fix: validate consistency findings and retain partial review coverage * fix: keep partial posting payloads honest across legacy and advisory reports * docs: record review validity and partial coverage for Agent-Field#1820
* fix: read complete bounded catalogs when connecting providers * changelog: record complete catalog connections for PR1822
* changelog: roll up v0.8.0 from current dev * changelog: the v0.8.0 rollup own entry for PR1821 * changelog: include complete provider catalogs in v0.8.0 roll-up
…eld#1823) * test: drain learned-quirk writers before simulating a restart * changelog: record the restart fixture ownership repair
…ield#1824) * test: drain learned-quirk writers before simulating a restart * fix: serialize learned-provider memo snapshots through replacement * changelog: record the restart fixture ownership repair * changelog: record ordered provider memo persistence
…eld#1825) * changelog: reconcile v0.8.0 with the merged restart repairs * changelog: record the v0.8.0 reconciliation PR
…ps a leading fence (Agent-Field#931) (Agent-Field#1807) * chat: one reader for a report's first prose line so every surface skips a leading fence (Agent-Field#931) A report that opens with a code fence used to draw three backticks on the tasks table, the home panels and the task record, while the landed card (fixed in Agent-Field#889) already quoted the sentence. The cause was two readers: the surface skipped the fence through firstProseLine, but the engine wrote TaskIndexEntry.Outcome through taskOutcome, which read the literal first line. Lift the fence-marker detection and the first-prose-line reading into one leaf package, internal/reportline, that both the surface and the engine import. taskOutcome, taskFirstSentence, switcherFirstLine and the renderer's mdFenceOpen all route through it; firstProseLine becomes a thin wrapper. A structural law pins that every path quoting a report's first line goes through the one reader, so a future hand cannot reach for firstLine and put the fence back. * chat: change entry for the one-reader fence fix (Agent-Field#1807) * chat: drop duplicated test table and merge the law's two AST helpers (Agent-Field#1807) firstProseLine is now a one-line delegate to reportline.FirstProse, so the Agent-Field#889 table in tui3 re-tested the same logic the reportline table already pins; keep the two card tests that prove the surface is wired to the reader. Fold the law's bodyCallsSanctionedReader and bodyCallsFirstProse into one bodyCallsAny(names...). --------- Co-authored-by: ZeroPoint95 <329227198+ZeroPoint95@users.noreply.github.com>
Agent-Field#1809) * tasks: pin the tasks-heading test clock to local zone so it is $TZ-stable (Agent-Field#1808) The window buckets days in the viewer's local zone on purpose (usageBucketStart, and the "THE DAY IS THE WRITER'S" law on SpendToday). The test built its fixture clock in a fixed -04:00 zone and asserted the chat manual quotes the rendered `since aug 11` verbatim, so once that clock was read as local on a host far enough east it crossed midnight and rendered `aug 12` instead — green on a UTC runner, red on a UTC+8 box. Build the fixture clock in time.Local so it agrees with the bucketing; verified identical under TZ from Pago_Pago to Kiritimati. * tasks: change entry for the $TZ-stable tasks-heading test (Agent-Field#1809) * tasks: pin every tasks-page fixture clock to local zone, not just one (Agent-Field#1808) The same fixed -04:00 fixture clock lived in five tasks-page test files, and the window buckets days in the viewer's local zone, so two tests already failed on a UTC+8 box — TestTheManualQuotesBothTasksOpeningHeadingsExactly on 'aug 11' vs 'aug 12', and TestTheTasksPageGroupsByWhatYouDoNext on the 'shift+← aug 2 – aug 25 →' window control. One shared cause (Agent-Field#176's lesson), so fix it everywhere: build each fixture clock in time.Local. Verified green across the full span of host zones from Pago_Pago to Kiritimati. * docs: clarify existing DST limitation in tasks change entry --------- Co-authored-by: ZeroPoint95 <329227198+ZeroPoint95@users.noreply.github.com>
* fix: ask an ask-here errand's approvals in its own pane A call inside home's `ask here` errand that the approval policy grades "ask" blocks inside the errand's session until that agent is answered. errandEvent had no case for EventConsentRequest, and nothing else holds the errand's agent, so the errand sat `working` on a question no screen drew, and a `1` pressed at it went into the follow-up box. - The pane now draws the approval under the call it is about, with the conversation's own question builder and renderer: `1 allow once` and `3 deny`. There is no `always` from the pane. - The answer goes straight to the errand's agent (ResolveConsent), not through the block's door, whose receipt lands above the window's own box and whose `c change` would be answered by the window's engine. - The row says `waiting on you` and sorts first; the live block gives way while the turn waits; the call's row keeps `allowed`/`denied`. - The block's settle guard applies to the approval's digits and clicks, so a digit typed into a follow-up cannot allow an unread command. - Approvals are dropped when the turn ends; several in one step are asked oldest first. Results pair to rows by call id. - errandWait is renamed waitErrand so the harness's waiter law sees it and a test can hold a gated stream open. - asking-from-home.md says all of this, and no longer sends approvals to `continue as a conversation`, which ends the waiting call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: hold the ask-here card to the question block's guards Home's `ask here` pane routed its standing card's keys straight into the block's router, past the guards the block keeps in front of it. - While a correction was being typed after `o`, the card still owned `1`, `3` and `0`: "make it 10 tomorrow" answered it yes at the `1`, set the reminder up as first proposed and lost the rest. Every key is text while the change is written now. - The card took a key or a click the instant it appeared. It now keeps the block's settle guard, counted from the first frame that drew it. - Its answer went through the block's door, which files a receipt above the window's own box, in a conversation that never asked. A question marked `elsewhere` leaves no receipt and counts no yes. - asking-from-home.md says all three, names the change key `o` (it said `c`), and two probes pin the asker's words. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * changelog: ask-here pane approvals and card guards (Agent-Field#1833) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * changelog: keep the Agent-Field#1833 entry title under 100 characters Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: a correction owns every key, and the card re-arms after an approval Review of Agent-Field#1833. - While a correction is being written after `o`, the box owns every key, approval included. With a card and an approval up together, "make it 10" allowed the call at its `1` and left "make it 0" in the box. - An approval arriving zeroes the card's settle stamp, so the card's answers settle again when they come back. A `1 1` allowed the call and set up the reminder in the same instant. - The routing comment names the change key `o`, not `c`. - The manual's run-on heading is two sections. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…do (Agent-Field#1834) * fix: make home's ask-here hints and the /help digits name what the keys do - alt+enter on home belongs to the router (the composer layer); drop the unreachable alt+enter arm from home's ask-here case and keep ctrl+enter. - An errand row's foot says `enter or → answer this ask here` (and `enter answer this ask here · esc clear` over a draft); tab on the row is the next place. - The pane's `tab or esc back to the list` stays the last clause, so a 60-column frame keeps it; `/ commands` is not named while the pane has the keyboard. - /help numbers each place (`1 home · 2 AI teams · …`) instead of calling placeOrder the tab bar's order. - The manual pages say the same: ctrl+enter vs alt+enter, the row and pane feet, and which digit opens which place. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: give the ask-here pane's box its own words, and raise its sheet on a phone - While an errand's pane holds the keyboard, the box under it says `type a follow-up` (or `type the change` after `o` on a card) instead of home's `type to search or start something new`. - On a phone-width window an errand's sheet now follows the pane's focus, so `ask here`, its chord and `→` on the row show the box the keys type into; before, only `enter` raised it and typed letters went nowhere visible. - The phone sheet's box draws the same sentence at rest. - Manual: the pane's box, ask here on a phone-width window, and the card's correction key (`o`, not `c`). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: home's arrows never cross columns; say what → opens instead - keys.md, home.md, commands.md and places.md said ←/→ cross home's columns. Since 2026-09-17 every stop is in the field's one column and the rail is never walked: → opens the row's verbs, ← closes them, and on an ask-here row → hands the pane the keyboard. - The strip's words now match the code (x delete, p pause, s stop it), and the project row's `its chats` verb (removed in Agent-Field#1422) is no longer promised. - The phone inbox's folded project opens with → and folds with ←. - Comments in home.go, placekeys.go and verbstrip.go no longer cite the deleted homeView.crossColumns. - A truth test fails if any section repeats the crossing claims; three probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: home's ctrl+e asks to delete, it does not close a tab - keys.md said ctrl+e closes, archives and reopens a conversation, that the strip's verb is `x close`, and that the card legend says `ctrl+e close`. Since Agent-Field#1750 ctrl+e on a conversation row opens the delete confirmation (legend `ctrl+e delete`), and enter reopens a dimmed row. - homeArchiveRow's comment says no key reaches it; tests still use it to make closed rows, so it stays. - A truth test fails if a section repeats the old claims; one probe, and the places heading for the box's rule gains the asker's words. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * changelog: entry for Agent-Field#1834 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * review: /help's digit row in commands.md, the o key, and leftovers - commands.md quoted /help's old `established shortcut order` row; it now quotes the numbered list, and a truth test refuses the old phrases. - asking-from-home: the way back is the last clause except while a change is being typed after `o`. - Comments call the correction key `o`, and the ctrl+x comment no longer says → crosses columns. - Remove the e2e rig's unused altEnter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: let the pane's card settle before the box-sentence test presses o Agent-Field#1833's settle guard drops a key that lands with the card, so the test pins the clock and moves it past questionSettle once the card has been drawn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…nd watches (Agent-Field#1831) * automations: the design, and the core — schedule, store, presence, clock The design (docs/design/automations/DESIGN.md) replaces standing items and the v1 scheduler with one mechanism: a schedule, an optional look, an action, run only while a codeaf window is open. audit-notes/standing-and-schedules.md is the evidence it answers. internal/automation is the object and its machinery, with nothing wired yet: - schedule: five-field cron read in the automation's own zone, stepping in absolute time so the wall clock never goes backwards (a 01:30 line runs once on the night the clocks fall back); intervals on an anchored grid, so late runs never drift the next one; lines that never match are refused. - store: SQLite (WAL) with the person's half as a document and the clock's state as guarded columns; a slot becomes a run in one transaction and can never be taken twice; a change counter every window reads from. - presence: one OS lock per open window, so "is any window open?" is answered by the kernel, not a heartbeat. - clock: one holder at a time, catch-up once and marked late, one run per automation at a time, two pieces of work at once, watches that speak on the change to yes, explicit outcomes read from reports and context causes, and a clean stop when the last window closes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the engine side — the automation tool, its card, and the runner - `automation` (propose, list, pause, resume, delete, run, history) is on a conversation's belt when a store is behind it, and never on a task's or a run's: nothing an automation does may arm another. Every answer ends with the time. - The card is one question kind (`automation`) built once in the session: 1 Save · 2 Save and run it now / check it now (not for reminders or worktree work) · 0 Don't save · words are a correction. It shows the schedule in words and exactly, the first run, and a watch's estimated daily cost when the price is known. Save and run it now hands the action back to do in this turn, so approvals reach the person and "always" is banked for later runs. - The runner looks (a command with the provider keys stripped, a bounded file listing that says what changed since the last decided look, or a tool through the person's own gate with its connected account put to use first), judges every look on the low-tier seat and bills it to the usage ledger against the automation, and runs work as a session built from the person's own config: their approval rules with nobody to ask, the first refusal for want of the person stopping the run as your call, a money cap, and an outcome that comes only from `automation_report`. - File watches keep a small memo between looks so a change made while codeaf was closed is still seen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory always: the store keeps rules as memories marked always - A memories column, always_on, declared for new stores and added to old ones by migrateMemoriesAlways inside one immediate transaction, with a partial index over active rules; the owner migration now checks its column inside its transaction too, so two opens of one old store at once cannot both alter the table. - memory_always events set and clear the flag; the add and supersede payloads carry it, a supersession keeps the retired row's rule, and the replay and the sync fold both apply it. - The write door promotes a remembered row when the same words are asked for always, and never demotes a rule. - AlwaysMemories reads the rules for named owners in one order (person, machine, project; oldest first); rules are no longer router candidates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the clock process, window presence, and no timers on the machine - `codeaf clock` (hidden machinery, like `engine`) is the one process that runs automations: it takes the lock or leaves, builds each run's configuration through the same assembly a conversation uses (extracted from openV3Launch as v3ConfigFor, which finds no conversation and starts nothing), runs keyless when there is no key so reminders still work, and retires when its binary is replaced and nothing is running. - Every window holds presence for as long as runSurface runs and starts a clock when none holds the lock, checking again every 30s. - Conversations get the automations door, one store handle per process. - Every start of this build takes the old launchd/systemd timers (tick and wake, both names) off the login, acting only on definition files it finds under HOME. `codeaf tick` stays as a hidden verb that does nothing, so a timer an older build installed ends quietly until it is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the window side — the card, the run lines, notifications and the store watcher Every window reads the automations store on a two-second beat: a finished run draws one dim line in the conversation that made it, the first window on the machine to claim a run raises the desktop notification, and the quit question gets its snapshot. Local windows hold presence themselves; the doors to another machine will hold it there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory always: rules ride every turn and task, /always, the memory place's a - Session: remember gains always; a rule settles through the one write path and lands as a preference; an ordinary line never sees, rewords or retires a rule; /always (RememberAlways) asks nothing; AlwaysMemories lists the rules in force; a conversation with no project of its own keeps its rules for the person and says so. - The model's own rule is a question: internal/approval's KeepsARule is a floor under every allow (and under no policy at all), no memo or guardian answers it, its card offers no standing yes, and with nobody to ask it is refused in words the model can act on. - Injection beside the standing orders: an <always> block in message[0] (no ages, stable order, 12 rules / 2,400 runes, kept on a failed read, lean profiles included), task briefs, plan-born run workers and codeaf do; rules skip the binding reads and the memory tidy. - Wire: Memory.RememberAlways, Memory.Always and Memory.SetAlways. - TUI: /always and its listing, an always fact on rule rows, a on the strip and the foot, and the card. - Manual: three sections on what-i-remember and the probes that ask how to make a rule; PERF.md records the rules block's bounds. - The fixed prefix is over its cap by 152 bytes on this branch alone; the waivers are not raised (the standing deletion pays it back). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: delete the v1 resident's scheduler The v1 resident kept a scheduler nothing could reach: no surface has made a charter since Agent-Field#469, and no production code installs its timer. It still ran through `codeaf wake`, advertised in --help as "run one full background pass by hand", and doctor read its timer. docs/design/automations/DESIGN.md replaces all of it; this removes it. Gone: - internal/resident: the watch engine and sentinel seam (watch.go), charter commands and the timer offer (charters.go), tenure, the practice loop, the retrospective's charter proposals and hygiene nudges, and every hook in the tick, the quiet gate and the splice (the charter draft on compile). - internal/store: charter.go, charter_spec.go, tenure.go, standing_watch.go, the practice loop's half of practice.go and the dead notebook reads, the charter command kinds, the proposal-appetite trait and the "proposals" reversal class, and the three charter question categories. - internal/head: the temporal compiler (standing.go), the charter half of question answering (charters.go, now answers.go), rule targets in change/stop/recall/open/status, the `standing` belt read, and the money rails for standing proposals. - internal/watchdog, and internal/registry (no importers at all). - cmd/codeaf: wake's pass, the sentinel client, the doctor rows `background timer` and `standing`, and the wiring in resident_build.go. - config: practice_budget_usd, practice_idle, brief_after and tenure_after, their rows, resolvers and env-table lines; the keys are retired, so a profile holding one is not told it is ignored. `codeaf wake` stays dispatched as a hidden verb that does nothing and exits 0, because a timer an older build installed keeps running it until the first start of the automations build removes it, and an unknown verb exits 1. Old stores still open and rebuild. Every v1 event stays in the journal and replays as an unknown kind; the `charters` table is no longer created but is never dropped, and nothing reads it beyond a tolerant lookup naming an older build's work in a self receipt. nodes.charter_id, Provenance.CharterID, agent_questions.origin_charter_id, the brief's charter item and the practice rounds' question replay all stay, because removing them is a migration that says nothing new. A charter question an older build left open lapses on the next pass, and a queued charter command is refused in a sentence rather than by its spelling. internal/store/legacy_scheduler_test.go pins both halves. The resident's own manual loses standing-goals.md and says what happened in daily-rhythm.md; the chat manual's `codeaf wake` section becomes one short section with `codeaf tick`, and the doctor section loses its timer row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: over --host and --at — the far machine's store on the wire, and its clock kept for an attached window A window over --host or --at sits in front of a conversation on another machine, whose automation tool saves into that machine's store and whose clock runs only while a window is open there. So such a window now reads and changes the far machine's automations, and the far clock counts it. - Protocol 21: thirteen Automations.* calls, one per tui3.AutomationsSeam function, answered from the engine machine's store; Welcome.Automations and Welcome.AutomationsZone say the engine has them and in which zone a rhythm is read; Hello.Window says the connection is a window. - The engine door supplies remote.EngineAutomations (the store, the zone, and keepAutomationsWindow as HoldWindow). A Window hello holds presence before it is welcomed and lets it go on every road out; an engine with no store advertises nothing and refuses every call. - hostOptions builds the seam from the client when the welcome says so, and the zero seam otherwise. Only the --host and --at boot dials say Window; the beside dials and the local engine road never do, which a structural law now holds. - Manual: a section on which machine runs them and when they stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the v1 scheduler is gone docs/STANDING.md opens with a note saying what was removed, what an older store keeps, and that docs/design/automations/DESIGN.md replaces it; the rest of the page is left as history. docs/FEATURES.md loses the entries that described the removed machinery as working: the timer offer, charter proposals, the practice loop, probation and tenure, and `codeaf wake`. The entries that only mentioned it (the modality rail, the retrospective, the arrival brief, curiosity receipts, competence, doctor and the environment list) now say what the code does. docs/LIMITS.md drops the practice carve-out row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the demo home seeds automations, not standing orders cmd/codeaf-demo-home now makes seven automations across its three projects (two reminders, the morning sweep on a cron line, a dependency bump in a separate worktree, a command watch on CI, a once-watch on pricing.json, and a paused one) and replays the clock over a fortnight of open windows, so their runs carry every outcome, late catch-ups, and run folders that are really on disk. Three were said in seeded conversations, whose Words are turns those journals have, so their lines land when those conversations open. The spend ledger books each run's own cost under UsageLine.Automation in place of the standing check line, and the package no longer imports internal/standing. internal/automation gains Store.SetClock: the one door a fixture needs to write a history through Create, Take, Start and Finish at the moment it happened. Nothing in the product calls it. A demo launch, and the hand-open line it prints, set CODEAF_NO_AUTOMATIONS=1, so no window opened on the demo starts the clock: the seeded work would otherwise run for real on the person's own key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the place, the typed command and the quit warning; standing leaves tui3 /automations replaces the standing place in the same slot: the list with each automation's schedule and last run, its history, and → run, pause, stop, edit, delete and open. The exact typed forms add, edit, run, pause, resume and delete, and an add or edit ends on a card like the model's. Leaving the last window with a run in hand warns once. Home's next panel and since-you-left read automations; ask here keeps working, re-homed to its own errands folder, with the automation card in its pane. Every standing surface in tui3 is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the hints teach automations, and the standing words leave the place prose Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the standing engine leaves the session, the doors and the wire - internal/session: the stand tool, its card, inbox, world section, mark and runner are deleted; the belt fact and the page's paragraph now name `automation`, and the prefix waivers fall to the measurement - automation runs borrow the brain read-only, as standing firings did - the memory tidy rides the clock (automation.Tidy), gated on MachineIdle - the sweep's fourth rule reaps stale errands and keeps any an automation was saved from - an automation card answered from another window takes every key its own card drew (`2` was refused at the doorstep) - cmd/codeaf: the ticker, the background repair, the standing seam and the host's standing cache are gone; the clock carries the tidy - remote: Standing.* methods, ResolveStanding and the marked submit leave the wire; the held kind goes; the surface-door ledger drops to 18 - config: the background-checks row is retired with its key - run: worker briefs close on the person's rules alone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: watch names the idea, and the standing purpose goes - `watch`'s description said lasting checks were `stand`'s, a tool that is gone; it now names an automation without naming a verb some belts lack - the unused standing-check call purpose leaves; the replay tool still reads old logs that carry it - the fixed prefix falls another 8 bytes and its waiver with it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the docs say what was built - the design doc gains the typed grammar, the → keys, the quit warning as shipped, the store's notification claim, the kept `ask here` errands, the read-only brain and the tidy on the clock; the watch cost estimate it promised was never built and goes - the guide, the README, FEATURES, LIMITS and the memory docs name automations and `/always` where they named standing orders; the README's standing screenshot goes with the page it showed - AMBIENT and STANDING-ORDERS are marked superseded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the kind's answer row is said to be the superset it is Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the reading says why it is handed its palette Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * e2e: automations replace standing orders in the end-to-end suite Nothing in internal/e2e imports internal/standing or leans on a standing door any more, so the package builds once those are deleted. - The host guard proves the old-timer removal touches only the throwaway login: testdata/oldtimers runs RemoveOldTimers as a real program behind the guard, and the developer's tick and wake files, both names, are hashed around it. The guard also stands in for osascript and notify-send, and sets CODEAF_NO_AUTOMATIONS=1 on every launch whose scenario does not name it. - The shared world keeps no ambient store and no standing answers; say and drain take none, and decline an automation card if one ever comes. - The three standing lanes are deleted. TestAutomationsE2E replaces the three TestTUIE2E subtests that were about standing orders, with no key: ask here ending on an automation card (wide and narrow), and a typed reminder said by the clock into its conversation, as a notification and on the automations place, then the clock leaving on its own. - The words table drops the standing rows, respells the ones automations renamed, and catches up with home's activity heading, the seven-place bar and the Spending tab's per-chat label; testHomeShape, testAnswerFromHome and testOneSpendFigure read what is drawn now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the tui3 and session test builds compile again Three test files still named what the standing removal took away, so neither package's tests built at this commit and no manual gate in them could run: notice_test.go proved a retirement event that no longer exists, and the usage tests asked for a spend subject that is now SubjectAutomation. - notice_test.go: the gesture is /automations, which fires eventAutomationsOpened. - usage_ledger_test.go: an automation's run writes its line under the automation's id, and the rollup names the automation. - usage_spend_test.go: the automation row and its subject word. These are byte for byte the versions 61022e9 carries, so the two branches agree on them when they meet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the e2e timing notes stop promising a standing pass Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the chat manual says what replaced standing orders The chat corpus still taught standing orders — /standing, the stand card, keeping an eye, the OS timer and `codeaf tick` — after automations had replaced them. The chat answers from these pages alone, so it would have offered a page, a key and a timer that no longer exist. - automations.md is new: reminders, scheduled work and watches; the card and its answers; schedules and cron; /automations and its → verbs; history and what a run came to; where the news arrives; the clock that runs only while a window is open, missed runs marked late; cost limits; worktree or checkout; the typed /automations forms; ask here; rules as memories marked always; the automation and automation_report tools; where standing orders went; and what automations cannot do. - keeping-an-eye.md and standing-orders.md are deleted. Every other page that described standing — home, keys, commands, places, screen, asking-from-home, the remote pages, models-and-cost, questions, tasks, what-i-can-do, what-i-remember, hints-and-tips and the rest — now says what the automations code does, quoting its strings. - chat_test.go: the forty-nine probes that reached a deleted page are pointed at the page that answers them now, and fifty-six probes are added in the asker's words. The rerun and due-time tests follow. - truth_test.go no longer imports internal/standing: the standing facts leave, and automation.DefaultTime and automation.DefaultUSD are pinned where the pages quote them. - asked.go's wants follow the pages; lawregistry_test.go drops the two laws filed against keeping-an-eye; session's manual gate opens an automations store so `automation` is checked, and a second gate builds a run's belt so `automation_report` is too. - The e2e due-time subtest still reaches home, and waits for the sentence that says where an automation's next time is shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: internal/standing is deleted Nothing imports it any more: the session, the doors, the wire, the config, the manual's truth table and the end-to-end suite have all moved to internal/automation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: home's tip leads with the command A home tip says a key or a command first, and the one that taught saying an automation did not, so home's row broke its own law. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a collection cannot gain a standing item The kind names nothing codeaf runs any more. A row an older build wrote can still be found and taken out; the schema keeps the kind so an older build on the same machine still opens the database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a conversation switched to is told what it missed The missed runs were gathered only on a window's first reading, so a conversation switched to in a window already open never heard them. Now any conversation that comes to the front is asked about once, and a run a window has drawn is not drawn twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the manual says when an errand that went nowhere is cleared Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: gofmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the complexity ratchet holds the automations engine The ratchet walked the standing ticker and inbox, which are gone; it now walks the automations clock, store and runner. The run's Work held 25 decisions against a ceiling of 15, so it is split along its own phases: the run's configuration, the turn watched for the two reasons to stop, and what it came to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: comments stop describing standing orders as live Comments in cmd/ and internal/ (internal/standing and internal/e2e left alone) that still described the standing feature as current now say what the code does: the automation tool, /automations, `codeaf clock` and the rules marked always. Historical records are kept, with doc links to deleted symbols turned into plain text or pointed at the replacement, and every bracketed link a rewritten comment names resolves. Comments only: the token stream of every changed file is identical outside comments, apart from one stray blank line in effortscope.go's import block that gofmt removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a run of work stops at the daily spending limit Standing firings were held to the person's daily limit; an automation's work run is shaped like a task, which the turn's check passes over, so it spent past the limit. It now asks before anything is made for it and reads `your call` when the limit is reached. A watch's looks are not held to it: each costs a fraction of a cent, and a refused look is news. The design doc gets back the watch cost estimate, which is built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the suites pass without standing orders - home settles its phone shape before it builds again; the band read that used to do it went with standing orders - `/automations` has its fates on home: the place bare, a conversation for `add` and `edit`, home's own line for the id verbs - `automation_report` is communication, and both automation tools have a folder-hold disposition; `usd` is a fractional argument - the dead standing fields, the backlog fold, the held kind, a separator and three band orders are removed - tests that still named standing words, `/standing` as a door or the standing ladder stamper now read the automations surface Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: ask an ask-here errand's approvals in its own pane A call inside home's `ask here` errand that the approval policy grades "ask" blocks inside the errand's session until that agent is answered. errandEvent had no case for EventConsentRequest, and nothing else holds the errand's agent, so the errand sat `working` on a question no screen drew, and a `1` pressed at it went into the follow-up box. - The pane now draws the approval under the call it is about, with the conversation's own question builder and renderer: `1 allow once` and `3 deny`. There is no `always` from the pane. - The answer goes straight to the errand's agent (ResolveConsent), not through the block's door, whose receipt lands above the window's own box and whose `c change` would be answered by the window's engine. - The row says `waiting on you` and sorts first; the live block gives way while the turn waits; the call's row keeps `allowed`/`denied`. - The block's settle guard applies to the approval's digits and clicks, so a digit typed into a follow-up cannot allow an unread command. - Approvals are dropped when the turn ends; several in one step are asked oldest first. Results pair to rows by call id. - errandWait is renamed waitErrand so the harness's waiter law sees it and a test can hold a gated stream open. - asking-from-home.md says all of this, and no longer sends approvals to `continue as a conversation`, which ends the waiting call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the word stands on the tab bar, between memory and spend A place that appeared only while somebody stood in it was a room nobody knew was there. Eight words need 84 columns, so a narrower frame folds spend and settings behind more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: banners through the terminal, closing pauses, and watches find the key What the owner's walkthrough of the first build found, fixed: - A banner is raised whether or not codeaf has the keyboard, so `r` on a reminder raises one too. In iTerm2 it is iTerm2's own (OSC 9), in Ghostty, kitty, WezTerm and foot the terminal's OSC 777, and clicking it brings the tab back. Elsewhere it is osascript with a sound, or notify-send with the logo. The first banner on a machine names the sending app once, linked to Notification settings. A codeaf-branded macOS banner needs a Developer ID: macOS 26 refuses an ad-hoc-signed applet silently. - A run's line is also said on the message line of home or the place in front. - Quitting never asks. A run closing codeaf cut off is told to nobody and runs again, once, when a window next opens. - A watch's check passes over a model whose service has no key, down to the conversation's own model, and names the model and service when none is reachable. The clock re-reads the saved key before every run, and follows the newest window's environment (a salted fingerprint, never a value), so a key exported in one shell and not another no longer decides it. - The typed form reads `at 6pm`, `at tomorrow 9am` and `at monday 9am` without quotes. - The clock no longer runs the memory tidy, which the memory rework rules out. - Home's since-you-left whisper no longer says watches run while codeaf is shut. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the demo's cut-off run is one the person stopped, and the row-zero law starts at 84 columns A run codeaf closing cut off now picks up again, which the demo's replay of the rhythm cannot express. Eight words on the bar need 84 columns, so that is where the bar is promised never to move. The since-you-left whisper says what happened rather than what landed, which a first look must not claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the change entry for Agent-Field#1831 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a run's whole result is read in its history, and its banner carries it The run under the cursor in an automation's history shows its full report in ordinary text, and the history opens on the newest run. A banner says what the run came to and up to 180 characters of its report, without repeating the title. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the review's fixes - Deleting an automation stops its run in hand: the clock asks whether each run's automation still exists, since the delete takes the run rows (and any stop request) with it. - A rhythm of days that would overflow a duration is refused, not wrapped. - A files watch's walk checks its budget and its run's context on every entry, so a rarely matching glob over a whole home no longer walks it all. - The judge's client is kept per model and account, so a replaced key is used. - A window's presence file is locked and written before it is renamed into place, so a counter can no longer remove a window being opened. - `codeaf do` reads the rules before its deadline starts. - A typed id needs four characters, and the refusal says where the id comes from. A ~ folder crosses unexpanded and the store reads it as its own machine's home, so a line typed over --host names the far machine's folder. - Each automation keeps its last hundred runs; forgotten and deleted runs' folders go, except a folder holding a worktree, whose changes are the person's to review. - A watch's banner says its own line, not what its look saw. - The old timers' files are removed before their jobs are unloaded, by label. - Stale docs and comments; the audit note is dropped from the change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the guide's tool table names automation, not the removed stand Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* automations: the conversation can change one in place The `automation` tool had no op that changes an existing automation, so "move my water reminder to 5pm" could only propose a second one beside the first, often a finished reminder left standing in /automations. - `change` takes an id and only the fields that change, lays them over the saved automation, and raises the same card the typed edit does: `save this change?`, `1 Save` and `0 Don't save`. Save goes through Store.Update, which works a new schedule out from now and wakes a finished one-time reminder. - An id on a card is what makes it a change, so AutomationHead and AutomationOptions decide it once for both doors; the typed edit now reads its head and answers from session. - The page tells the model one that exists is changed, never proposed again. The bytes were paid out of the tool description's repeat of the watch fields; both prefix arms are 22 bytes lighter and both waivers fall by that (PERF.md). - The manual's "Change an automation" leads with asking, and the denial that the chat had no verb for it is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * changelog: the conversation can change an automation in place (Agent-Field#1829) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a change's card promises only the next run its save gives Review of Agent-Field#1829. A `when` re-sent as it was counted as a new schedule, so the card worked out a next run from now while Store.Update, which only reschedules on a different moment, rhythm or zone, kept the old one: a finished watch's card promised a run it never got, and an hourly one's promised a slot off its grid. - automation.ScheduleChanged is now the one reading of "a different schedule", and the change op asks it before counting a `when` as new. - A rhythm keeps its stored zone exactly, empty (the machine's) included, so re-sending the same `every` does not give it a zone and move it. - The refusal names title and words too; a change's card says `next run`. - DESIGN.md says the conversation's `change` raises `save this change?`. - Tests: the same `when` re-sent, deleted while the card is up, and a paused one staying paused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…lback (Agent-Field#1832) * update: releases come from one repository; retire the former-name fallback - The updater (Select, TagPublished, Install) and scripts/install.sh no longer ask the repository's former name after a 404 from the release repository. That name is only GitHub's redirect to the same repository (same repository id), so it never held a release the real one lacks; asking it could only ever reach a repository created under that name later. - Install always downloads from the release repository, whatever repository a caller wrote on the release. - The former asset name is still tried inside the same release, for v0.1.0, the one stable published before the rename. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: record the one release repository for Agent-Field#1832 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * update: answer the Agent-Field#1832 review - Drop the stale H10 comment that described the old fallback above the helper that now forbids it. - selectRelease reads the release repository itself and assetURL builds every download address from the constant, so no Release field is ever an address. - The fake servers' request lists in the new update tests are kept under a lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ore the chat opens (Agent-Field#1826) * update: a released codeaf installs the newest stable and restarts before the chat opens - A stable build in a file named codeaf, with automatic updates on, now looks before the chat opens (cached a day, otherwise at most 1.5s, and a look that got no answer is not waited on again for an hour), installs within 20s with a progress line, and hands the terminal to the new build with the same arguments. ctrl+c, a slow download or a failure opens the build on disk. - Only that build is updated unasked (update.AutomaticFor): dev, staging, rc and source builds, devaf, stageaf and other file names are told on one terminal line and the chat's quiet line, and never replaced. Nothing runs without a terminal, under CI, or for --once. - `codeaf update --version <tag>` and `/update <tag>` pin the file at that release; a plain install unpins. The pin lives in the install record, so a file replaced by curl drops it. - The chat's countdown is kept as the fallback when the launch could not finish, and is now gated by the same rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: record what auto-update on launch changes for Agent-Field#1826 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * update: a finished install says one short line `codeaf <tag> installed · restart to use the new version`, in the transcript and the keys line alike, instead of the sentence about windows and engines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * update: answer the launch-road review - A launch that runs out of its 20s clock records the release as slow (AutoSlow); for a day the next launches leave it to the chat's background road instead of starting the same download again. - The name rule reads the file that would be overwritten, links resolved, on every platform; the check decides it off the frame and carries it as Available.Automatic for both launch roads. - A file already holding the release says "is already on disk · opening it" instead of claiming an install. - Windows Relaunch ignores console ctrl+c while it waits on the child. - Both spellings of the restart marker are cleared; the download meter draws only when stderr is a terminal; a --debug record opens after the launch's own update; Linuxbrew is a package manager. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…r silently (Agent-Field#1830) * automations: the design, and the core — schedule, store, presence, clock The design (docs/design/automations/DESIGN.md) replaces standing items and the v1 scheduler with one mechanism: a schedule, an optional look, an action, run only while a codeaf window is open. audit-notes/standing-and-schedules.md is the evidence it answers. internal/automation is the object and its machinery, with nothing wired yet: - schedule: five-field cron read in the automation's own zone, stepping in absolute time so the wall clock never goes backwards (a 01:30 line runs once on the night the clocks fall back); intervals on an anchored grid, so late runs never drift the next one; lines that never match are refused. - store: SQLite (WAL) with the person's half as a document and the clock's state as guarded columns; a slot becomes a run in one transaction and can never be taken twice; a change counter every window reads from. - presence: one OS lock per open window, so "is any window open?" is answered by the kernel, not a heartbeat. - clock: one holder at a time, catch-up once and marked late, one run per automation at a time, two pieces of work at once, watches that speak on the change to yes, explicit outcomes read from reports and context causes, and a clean stop when the last window closes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the engine side — the automation tool, its card, and the runner - `automation` (propose, list, pause, resume, delete, run, history) is on a conversation's belt when a store is behind it, and never on a task's or a run's: nothing an automation does may arm another. Every answer ends with the time. - The card is one question kind (`automation`) built once in the session: 1 Save · 2 Save and run it now / check it now (not for reminders or worktree work) · 0 Don't save · words are a correction. It shows the schedule in words and exactly, the first run, and a watch's estimated daily cost when the price is known. Save and run it now hands the action back to do in this turn, so approvals reach the person and "always" is banked for later runs. - The runner looks (a command with the provider keys stripped, a bounded file listing that says what changed since the last decided look, or a tool through the person's own gate with its connected account put to use first), judges every look on the low-tier seat and bills it to the usage ledger against the automation, and runs work as a session built from the person's own config: their approval rules with nobody to ask, the first refusal for want of the person stopping the run as your call, a money cap, and an outcome that comes only from `automation_report`. - File watches keep a small memo between looks so a change made while codeaf was closed is still seen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory always: the store keeps rules as memories marked always - A memories column, always_on, declared for new stores and added to old ones by migrateMemoriesAlways inside one immediate transaction, with a partial index over active rules; the owner migration now checks its column inside its transaction too, so two opens of one old store at once cannot both alter the table. - memory_always events set and clear the flag; the add and supersede payloads carry it, a supersession keeps the retired row's rule, and the replay and the sync fold both apply it. - The write door promotes a remembered row when the same words are asked for always, and never demotes a rule. - AlwaysMemories reads the rules for named owners in one order (person, machine, project; oldest first); rules are no longer router candidates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the clock process, window presence, and no timers on the machine - `codeaf clock` (hidden machinery, like `engine`) is the one process that runs automations: it takes the lock or leaves, builds each run's configuration through the same assembly a conversation uses (extracted from openV3Launch as v3ConfigFor, which finds no conversation and starts nothing), runs keyless when there is no key so reminders still work, and retires when its binary is replaced and nothing is running. - Every window holds presence for as long as runSurface runs and starts a clock when none holds the lock, checking again every 30s. - Conversations get the automations door, one store handle per process. - Every start of this build takes the old launchd/systemd timers (tick and wake, both names) off the login, acting only on definition files it finds under HOME. `codeaf tick` stays as a hidden verb that does nothing, so a timer an older build installed ends quietly until it is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the window side — the card, the run lines, notifications and the store watcher Every window reads the automations store on a two-second beat: a finished run draws one dim line in the conversation that made it, the first window on the machine to claim a run raises the desktop notification, and the quit question gets its snapshot. Local windows hold presence themselves; the doors to another machine will hold it there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory always: rules ride every turn and task, /always, the memory place's a - Session: remember gains always; a rule settles through the one write path and lands as a preference; an ordinary line never sees, rewords or retires a rule; /always (RememberAlways) asks nothing; AlwaysMemories lists the rules in force; a conversation with no project of its own keeps its rules for the person and says so. - The model's own rule is a question: internal/approval's KeepsARule is a floor under every allow (and under no policy at all), no memo or guardian answers it, its card offers no standing yes, and with nobody to ask it is refused in words the model can act on. - Injection beside the standing orders: an <always> block in message[0] (no ages, stable order, 12 rules / 2,400 runes, kept on a failed read, lean profiles included), task briefs, plan-born run workers and codeaf do; rules skip the binding reads and the memory tidy. - Wire: Memory.RememberAlways, Memory.Always and Memory.SetAlways. - TUI: /always and its listing, an always fact on rule rows, a on the strip and the foot, and the card. - Manual: three sections on what-i-remember and the probes that ask how to make a rule; PERF.md records the rules block's bounds. - The fixed prefix is over its cap by 152 bytes on this branch alone; the waivers are not raised (the standing deletion pays it back). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: delete the v1 resident's scheduler The v1 resident kept a scheduler nothing could reach: no surface has made a charter since Agent-Field#469, and no production code installs its timer. It still ran through `codeaf wake`, advertised in --help as "run one full background pass by hand", and doctor read its timer. docs/design/automations/DESIGN.md replaces all of it; this removes it. Gone: - internal/resident: the watch engine and sentinel seam (watch.go), charter commands and the timer offer (charters.go), tenure, the practice loop, the retrospective's charter proposals and hygiene nudges, and every hook in the tick, the quiet gate and the splice (the charter draft on compile). - internal/store: charter.go, charter_spec.go, tenure.go, standing_watch.go, the practice loop's half of practice.go and the dead notebook reads, the charter command kinds, the proposal-appetite trait and the "proposals" reversal class, and the three charter question categories. - internal/head: the temporal compiler (standing.go), the charter half of question answering (charters.go, now answers.go), rule targets in change/stop/recall/open/status, the `standing` belt read, and the money rails for standing proposals. - internal/watchdog, and internal/registry (no importers at all). - cmd/codeaf: wake's pass, the sentinel client, the doctor rows `background timer` and `standing`, and the wiring in resident_build.go. - config: practice_budget_usd, practice_idle, brief_after and tenure_after, their rows, resolvers and env-table lines; the keys are retired, so a profile holding one is not told it is ignored. `codeaf wake` stays dispatched as a hidden verb that does nothing and exits 0, because a timer an older build installed keeps running it until the first start of the automations build removes it, and an unknown verb exits 1. Old stores still open and rebuild. Every v1 event stays in the journal and replays as an unknown kind; the `charters` table is no longer created but is never dropped, and nothing reads it beyond a tolerant lookup naming an older build's work in a self receipt. nodes.charter_id, Provenance.CharterID, agent_questions.origin_charter_id, the brief's charter item and the practice rounds' question replay all stay, because removing them is a migration that says nothing new. A charter question an older build left open lapses on the next pass, and a queued charter command is refused in a sentence rather than by its spelling. internal/store/legacy_scheduler_test.go pins both halves. The resident's own manual loses standing-goals.md and says what happened in daily-rhythm.md; the chat manual's `codeaf wake` section becomes one short section with `codeaf tick`, and the doctor section loses its timer row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: over --host and --at — the far machine's store on the wire, and its clock kept for an attached window A window over --host or --at sits in front of a conversation on another machine, whose automation tool saves into that machine's store and whose clock runs only while a window is open there. So such a window now reads and changes the far machine's automations, and the far clock counts it. - Protocol 21: thirteen Automations.* calls, one per tui3.AutomationsSeam function, answered from the engine machine's store; Welcome.Automations and Welcome.AutomationsZone say the engine has them and in which zone a rhythm is read; Hello.Window says the connection is a window. - The engine door supplies remote.EngineAutomations (the store, the zone, and keepAutomationsWindow as HoldWindow). A Window hello holds presence before it is welcomed and lets it go on every road out; an engine with no store advertises nothing and refuses every call. - hostOptions builds the seam from the client when the welcome says so, and the zero seam otherwise. Only the --host and --at boot dials say Window; the beside dials and the local engine road never do, which a structural law now holds. - Manual: a section on which machine runs them and when they stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the v1 scheduler is gone docs/STANDING.md opens with a note saying what was removed, what an older store keeps, and that docs/design/automations/DESIGN.md replaces it; the rest of the page is left as history. docs/FEATURES.md loses the entries that described the removed machinery as working: the timer offer, charter proposals, the practice loop, probation and tenure, and `codeaf wake`. The entries that only mentioned it (the modality rail, the retrospective, the arrival brief, curiosity receipts, competence, doctor and the environment list) now say what the code does. docs/LIMITS.md drops the practice carve-out row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the demo home seeds automations, not standing orders cmd/codeaf-demo-home now makes seven automations across its three projects (two reminders, the morning sweep on a cron line, a dependency bump in a separate worktree, a command watch on CI, a once-watch on pricing.json, and a paused one) and replays the clock over a fortnight of open windows, so their runs carry every outcome, late catch-ups, and run folders that are really on disk. Three were said in seeded conversations, whose Words are turns those journals have, so their lines land when those conversations open. The spend ledger books each run's own cost under UsageLine.Automation in place of the standing check line, and the package no longer imports internal/standing. internal/automation gains Store.SetClock: the one door a fixture needs to write a history through Create, Take, Start and Finish at the moment it happened. Nothing in the product calls it. A demo launch, and the hand-open line it prints, set CODEAF_NO_AUTOMATIONS=1, so no window opened on the demo starts the clock: the seeded work would otherwise run for real on the person's own key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the place, the typed command and the quit warning; standing leaves tui3 /automations replaces the standing place in the same slot: the list with each automation's schedule and last run, its history, and → run, pause, stop, edit, delete and open. The exact typed forms add, edit, run, pause, resume and delete, and an add or edit ends on a card like the model's. Leaving the last window with a run in hand warns once. Home's next panel and since-you-left read automations; ask here keeps working, re-homed to its own errands folder, with the automation card in its pane. Every standing surface in tui3 is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the hints teach automations, and the standing words leave the place prose Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the standing engine leaves the session, the doors and the wire - internal/session: the stand tool, its card, inbox, world section, mark and runner are deleted; the belt fact and the page's paragraph now name `automation`, and the prefix waivers fall to the measurement - automation runs borrow the brain read-only, as standing firings did - the memory tidy rides the clock (automation.Tidy), gated on MachineIdle - the sweep's fourth rule reaps stale errands and keeps any an automation was saved from - an automation card answered from another window takes every key its own card drew (`2` was refused at the doorstep) - cmd/codeaf: the ticker, the background repair, the standing seam and the host's standing cache are gone; the clock carries the tidy - remote: Standing.* methods, ResolveStanding and the marked submit leave the wire; the held kind goes; the surface-door ledger drops to 18 - config: the background-checks row is retired with its key - run: worker briefs close on the person's rules alone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: watch names the idea, and the standing purpose goes - `watch`'s description said lasting checks were `stand`'s, a tool that is gone; it now names an automation without naming a verb some belts lack - the unused standing-check call purpose leaves; the replay tool still reads old logs that carry it - the fixed prefix falls another 8 bytes and its waiver with it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the docs say what was built - the design doc gains the typed grammar, the → keys, the quit warning as shipped, the store's notification claim, the kept `ask here` errands, the read-only brain and the tidy on the clock; the watch cost estimate it promised was never built and goes - the guide, the README, FEATURES, LIMITS and the memory docs name automations and `/always` where they named standing orders; the README's standing screenshot goes with the page it showed - AMBIENT and STANDING-ORDERS are marked superseded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the kind's answer row is said to be the superset it is Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the reading says why it is handed its palette Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * e2e: automations replace standing orders in the end-to-end suite Nothing in internal/e2e imports internal/standing or leans on a standing door any more, so the package builds once those are deleted. - The host guard proves the old-timer removal touches only the throwaway login: testdata/oldtimers runs RemoveOldTimers as a real program behind the guard, and the developer's tick and wake files, both names, are hashed around it. The guard also stands in for osascript and notify-send, and sets CODEAF_NO_AUTOMATIONS=1 on every launch whose scenario does not name it. - The shared world keeps no ambient store and no standing answers; say and drain take none, and decline an automation card if one ever comes. - The three standing lanes are deleted. TestAutomationsE2E replaces the three TestTUIE2E subtests that were about standing orders, with no key: ask here ending on an automation card (wide and narrow), and a typed reminder said by the clock into its conversation, as a notification and on the automations place, then the clock leaving on its own. - The words table drops the standing rows, respells the ones automations renamed, and catches up with home's activity heading, the seven-place bar and the Spending tab's per-chat label; testHomeShape, testAnswerFromHome and testOneSpendFigure read what is drawn now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the tui3 and session test builds compile again Three test files still named what the standing removal took away, so neither package's tests built at this commit and no manual gate in them could run: notice_test.go proved a retirement event that no longer exists, and the usage tests asked for a spend subject that is now SubjectAutomation. - notice_test.go: the gesture is /automations, which fires eventAutomationsOpened. - usage_ledger_test.go: an automation's run writes its line under the automation's id, and the rollup names the automation. - usage_spend_test.go: the automation row and its subject word. These are byte for byte the versions 61022e9 carries, so the two branches agree on them when they meet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the e2e timing notes stop promising a standing pass Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the chat manual says what replaced standing orders The chat corpus still taught standing orders — /standing, the stand card, keeping an eye, the OS timer and `codeaf tick` — after automations had replaced them. The chat answers from these pages alone, so it would have offered a page, a key and a timer that no longer exist. - automations.md is new: reminders, scheduled work and watches; the card and its answers; schedules and cron; /automations and its → verbs; history and what a run came to; where the news arrives; the clock that runs only while a window is open, missed runs marked late; cost limits; worktree or checkout; the typed /automations forms; ask here; rules as memories marked always; the automation and automation_report tools; where standing orders went; and what automations cannot do. - keeping-an-eye.md and standing-orders.md are deleted. Every other page that described standing — home, keys, commands, places, screen, asking-from-home, the remote pages, models-and-cost, questions, tasks, what-i-can-do, what-i-remember, hints-and-tips and the rest — now says what the automations code does, quoting its strings. - chat_test.go: the forty-nine probes that reached a deleted page are pointed at the page that answers them now, and fifty-six probes are added in the asker's words. The rerun and due-time tests follow. - truth_test.go no longer imports internal/standing: the standing facts leave, and automation.DefaultTime and automation.DefaultUSD are pinned where the pages quote them. - asked.go's wants follow the pages; lawregistry_test.go drops the two laws filed against keeping-an-eye; session's manual gate opens an automations store so `automation` is checked, and a second gate builds a run's belt so `automation_report` is too. - The e2e due-time subtest still reaches home, and waits for the sentence that says where an automation's next time is shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: internal/standing is deleted Nothing imports it any more: the session, the doors, the wire, the config, the manual's truth table and the end-to-end suite have all moved to internal/automation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: home's tip leads with the command A home tip says a key or a command first, and the one that taught saying an automation did not, so home's row broke its own law. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a collection cannot gain a standing item The kind names nothing codeaf runs any more. A row an older build wrote can still be found and taken out; the schema keeps the kind so an older build on the same machine still opens the database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a conversation switched to is told what it missed The missed runs were gathered only on a window's first reading, so a conversation switched to in a window already open never heard them. Now any conversation that comes to the front is asked about once, and a run a window has drawn is not drawn twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the manual says when an errand that went nowhere is cleared Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: gofmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the complexity ratchet holds the automations engine The ratchet walked the standing ticker and inbox, which are gone; it now walks the automations clock, store and runner. The run's Work held 25 decisions against a ceiling of 15, so it is split along its own phases: the run's configuration, the turn watched for the two reasons to stop, and what it came to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: comments stop describing standing orders as live Comments in cmd/ and internal/ (internal/standing and internal/e2e left alone) that still described the standing feature as current now say what the code does: the automation tool, /automations, `codeaf clock` and the rules marked always. Historical records are kept, with doc links to deleted symbols turned into plain text or pointed at the replacement, and every bracketed link a rewritten comment names resolves. Comments only: the token stream of every changed file is identical outside comments, apart from one stray blank line in effortscope.go's import block that gofmt removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a run of work stops at the daily spending limit Standing firings were held to the person's daily limit; an automation's work run is shaped like a task, which the turn's check passes over, so it spent past the limit. It now asks before anything is made for it and reads `your call` when the limit is reached. A watch's looks are not held to it: each costs a fraction of a cent, and a refused look is news. The design doc gets back the watch cost estimate, which is built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the suites pass without standing orders - home settles its phone shape before it builds again; the band read that used to do it went with standing orders - `/automations` has its fates on home: the place bare, a conversation for `add` and `edit`, home's own line for the id verbs - `automation_report` is communication, and both automation tools have a folder-hold disposition; `usd` is a fractional argument - the dead standing fields, the backlog fold, the held kind, a separator and three band orders are removed - tests that still named standing words, `/standing` as a door or the standing ladder stamper now read the automations surface Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: ask an ask-here errand's approvals in its own pane A call inside home's `ask here` errand that the approval policy grades "ask" blocks inside the errand's session until that agent is answered. errandEvent had no case for EventConsentRequest, and nothing else holds the errand's agent, so the errand sat `working` on a question no screen drew, and a `1` pressed at it went into the follow-up box. - The pane now draws the approval under the call it is about, with the conversation's own question builder and renderer: `1 allow once` and `3 deny`. There is no `always` from the pane. - The answer goes straight to the errand's agent (ResolveConsent), not through the block's door, whose receipt lands above the window's own box and whose `c change` would be answered by the window's engine. - The row says `waiting on you` and sorts first; the live block gives way while the turn waits; the call's row keeps `allowed`/`denied`. - The block's settle guard applies to the approval's digits and clicks, so a digit typed into a follow-up cannot allow an unread command. - Approvals are dropped when the turn ends; several in one step are asked oldest first. Results pair to rows by call id. - errandWait is renamed waitErrand so the harness's waiter law sees it and a test can hold a gated stream open. - asking-from-home.md says all of this, and no longer sends approvals to `continue as a conversation`, which ends the waiting call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the word stands on the tab bar, between memory and spend A place that appeared only while somebody stood in it was a room nobody knew was there. Eight words need 84 columns, so a narrower frame folds spend and settings behind more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: one strength, one write door, every line in front of every turn (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: banners through the terminal, closing pauses, and watches find the key What the owner's walkthrough of the first build found, fixed: - A banner is raised whether or not codeaf has the keyboard, so `r` on a reminder raises one too. In iTerm2 it is iTerm2's own (OSC 9), in Ghostty, kitty, WezTerm and foot the terminal's OSC 777, and clicking it brings the tab back. Elsewhere it is osascript with a sound, or notify-send with the logo. The first banner on a machine names the sending app once, linked to Notification settings. A codeaf-branded macOS banner needs a Developer ID: macOS 26 refuses an ad-hoc-signed applet silently. - A run's line is also said on the message line of home or the place in front. - Quitting never asks. A run closing codeaf cut off is told to nobody and runs again, once, when a window next opens. - A watch's check passes over a model whose service has no key, down to the conversation's own model, and names the model and service when none is reachable. The clock re-reads the saved key before every run, and follows the newest window's environment (a salted fingerprint, never a value), so a key exported in one shell and not another no longer decides it. - The typed form reads `at 6pm`, `at tomorrow 9am` and `at monday 9am` without quotes. - The clock no longer runs the memory tidy, which the memory rework rules out. - Home's since-you-left whisper no longer says watches run while codeaf is shut. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the demo's cut-off run is one the person stopped, and the row-zero law starts at 84 columns A run codeaf closing cut off now picks up again, which the demo's replay of the rhythm cannot express. Eight words on the bar need 84 columns, so that is where the bar is promised never to move. The since-you-left whisper says what happened rather than what landed, which a first look must not claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: store, reflex and session tests for one strength (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: surface tests for one strength (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: wire, door and seeder tests for one strength (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the tidy, its clock types and the rule-consent floor are gone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the manual, the settings row and the last stale seams match one strength - what-i-remember is rewritten for one strength, the Memory tab, noticing and undo; the other chat pages stop describing the router, the always flag, the tidy, the shelf key and "memory is off" - the settings row is "notice things to remember" and applies from the next turn - the model's forget is seeded allow beside remember: both say what they did and /forget takes it back - a far engine with no store says "memory is unavailable on this machine" - a live switch to the lean profile keeps the memory block - the speed and no-change tests read the noticing pass instead of the removed pre-turn recall and extractor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the laws, the waivers and the docs follow one strength - lane.RoleRecall goes with the pre-turn recall: a role nobody calls is owed a deletion, and the provider tests that borrowed it use the tool role - the complexity ratchet watches the memory engine instead of the deleted contextual files; learnFromTurn, importMemoryFile and MemorySnapshot split under its ceiling - both prefix waivers fall to the measurement (52,519 and 44,915), in PERF.md too, and PERF.md's memory sections describe the one bounded block - tests that pinned the old shape (lean and tool-less pages dropped memory, an explained override became a memory, the settings row needed a restart) now pin the new one - the settings detail leads with what off does, and "remember across chats" still finds the row - docs/memory-architecture.md describes what memory is now; the contextual page is a pointer into history; the audit that started this is kept Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a test name stops spelling the old product name Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the change entry for Agent-Field#1830 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the change entry for Agent-Field#1831 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a run's whole result is read in its history, and its banner carries it The run under the cursor in an automation's history shows its full report in ordinary text, and the history opens on the newest run. A banner says what the run came to and up to 180 characters of its report, without repeating the title. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the Memories tab reads like Activity, and /forget is gone - the tab is "Memories"; typing "memory" still finds it, and eight tab words now need 86 columns - groups are rows of their own that open on → and fold on ←, never enter; lines hang on tree connectors with kept-by and age columns, and a pane reads the cursor row out on frames of 110 columns or more - the words being written on the add row or in a line's editor are drawn in that row, with the caret; before, they were typed into nothing visible - /forget and the undo stack behind it are removed: a person forgets and puts back on the tab, the model's forget stays, and every receipt made on the person's behalf says "see or forget it on the Memories tab" - wire Memory.ForgetQuery goes with the command, folded into Version 22 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the review's fixes - Deleting an automation stops its run in hand: the clock asks whether each run's automation still exists, since the delete takes the run rows (and any stop request) with it. - A rhythm of days that would overflow a duration is refused, not wrapped. - A files watch's walk checks its budget and its run's context on every entry, so a rarely matching glob over a whole home no longer walks it all. - The judge's client is kept per model and account, so a replaced key is used. - A window's presence file is locked and written before it is renamed into place, so a counter can no longer remove a window being opened. - `codeaf do` reads the rules before its deadline starts. - A typed id needs four characters, and the refusal says where the id comes from. A ~ folder crosses unexpanded and the store reads it as its own machine's home, so a line typed over --host names the far machine's folder. - Each automation keeps its last hundred runs; forgotten and deleted runs' folders go, except a folder holding a worktree, whose changes are the person's to review. - A watch's banner says its own line, not what its look saw. - The old timers' files are removed before their jobs are unloaded, by label. - Stale docs and comments; the audit note is dropped from the change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the catalogue test reads the Memories tab row Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the bound is the store's, held inside every write Review fixes for Agent-Field#1830. - the 4,800-rune bound, the line cost and the quoting move to the store (memory_room.go); every door that makes a line active — write, replace, reword, move, put back — is measured inside its write transaction against every block the owner reaches, so a line kept everywhere cannot overflow another project, and two writers with room for one admit one - duplicates are the target owner's only; a move or a replacement onto words already kept lets the copy go instead of keeping two, and a forgotten line cannot be moved - a store an earlier build filled past the bound lets its always rules, then project, machine and person lines ride (FitMemories), and the conversation says once how many don't fit - the model's remember and forget act only on a turn the person typed - a noticed line is said on the standing lane when the turn's stream has closed; an ask-here errand is not noticed - memories_fts stays this release for older engines still running - the settings row reads one spelling; the tab's foot over an empty filter says esc; the project lookup's wire error is no longer "no project" - stale comments, names and docs; the audit notes and the contextual doc go Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the guide's tool table names automation, not the removed stand Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: tell a person who had memory off, once per machine, that their lines ride The owner's ruling on R8: on the first start after the upgrade, a person whose memory row was off is told once that their N kept lines now ride every conversation they hold in, with the Memories tab to forget them. The marker is created exclusively beside the store on that first start whatever the setting says, so it is said once per machine and never to someone who turns noticing off later. No line changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a woken turn does not arm the model's verbs; the person's line does A turn a task's landing or a job's ending opens is empty and marked a wake, and it armed remember/forget because it carried no authored mark. The verbs now arm only on a non-empty line the person typed, on their line drained into a turn mid-way, and on the follow-up turn started to answer a line they typed in the last seconds of the turn before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a line noticed while its conversation is out of sight waits for the person The keeper holds a conversation's standing lane while another is on screen, and it drained memory's notices to nowhere. Memory's notices now say they are in no record (Event.Unrecorded); the keeper keeps them, files them with the conversation's parked receipts, and coming back draws them there. A turn's own lines wait for the turn to end, since coming back mid-turn replays them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a full refusal says whose block it would overflow; an already-kept correction is said The store's refusal now carries the owner it would overflow, and every door says it from the conversation's own view: here, for <project>, or in another project. Over --host the name in the text is compared instead. Noticing a correction that was already kept lets the old line go and now says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: test the bound on replacement, the unbounded import and a held second writer A seam inside the room check holds the first writer in its transaction; the second must not read the room until the first commits, and then finds none. The test fails with deferred transactions. Replacement is measured, and the legacy import is kept whole past the bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: words already kept are not put back twice; an unknown project counts nothing Putting back a line, or rewording one, onto words its owner already keeps active is refused with store.ErrMemoryKept, and the tab says "already kept". When the engine cannot say which project this is, the tab takes nothing from the failed answer and its head row draws no don't-fit count. Tests cover the tab's refusal words, the no-match hint and the no-project note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: a stub keeps the changelog's contextual-memory link; its terminal recipe goes CHANGELOG.md links docs/contextual-memory.md, so a one-line page says it is retired and where its contents are. The terminal acceptance recipe and its recorder tested the removed evidence layer, and are deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the manual, the change entry and the design say what round two changed Full receipts say whose block; words already kept are refused on put-back and rewording; an already-kept correction is said; a line noticed out of sight waits for the person; a woken turn arms the verbs only once the person types; an unknown project counts nothing that doesn't fit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the turn that answers the person carries it on its own message A stale flag could outlive a failed, declined, vision or abandoned turn and arm the next task's landing. The drain now reports whether it heard the person: mid-turn that arms the rest of the turn, and at the turn's end the follow-up wake's opening carries answersPerson. No agent state is left. A real-loop test fails a turn after a steer and checks the next wake is not armed; the keeper's turn notices, the hand-off on the way forward and the unrecorded mark are each pinned by a test that fails without them. The manual says an answer to a question on an idle conversation does not arm the verbs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the change entry records the re-measured prefix waivers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… is refused (Agent-Field#1837) * automations: a finished reminder moved later wakes again; a late save is refused Moving a FINISHED one-time reminder later with `e` on /automations could leave the row finished. Two things combined: - CommandLine wrote a one-time `at` to the minute, so an `in 2m` reminder (seconds precision) came back earlier in the box, and "the next minute" could be seconds away. - Store.Update saved a new one-time moment that had already passed while the card was up as the next run; the clock took it at once and the reminder was finished again a beat after the save. Fixes: - The edit line keeps a moment's seconds (and fraction); parseMoment reads them. - Store.Update refuses a changed one-time moment that is not after now. - An edit is refused for a past moment only when it moves the moment, so a finished reminder can be renamed. - automation.NextAfterChange is the one rule both doors' cards use for the next run, so the typed edit no longer promises a run to a paused automation or a fresh slot to an unchanged rhythm. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * changelog: a finished reminder moved later wakes again (Agent-Field#1837) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: review fixes — paused receipt, DST round trip, manual - A typed edit of a paused automation says "still paused — resume starts it again" instead of a next slot it does not run at. - The edit line writes a moment in a fall-back's repeated hour with its offset, so it reads back as the same instant. - A moment that passed in the current minute is refused to the second. - The Store.Update comment names errPassed, and that a zone-only change to a one-time schedule is refused too. - DESIGN.md narrowed: only a change is refused at save time; an add answered late still runs once. - Manual: a section on a change refused at save time and renaming a finished reminder, the refusal list, and three retrieval probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…gent-Field#1836) * tui3: make the switch and plan test fakes safe for the off-loop readers The -race failures in the held-send tests and the run-stop card test were in the test seams, not the surface. The kept conversation's watcher calls Attach from its own goroutine, and the door line asks PlanTasks, PlanTaskPage and the plan verbs off the loop; the real agents take their locks for all of these. The fakes did not: - switchAgent: Attach and its stop guard running/backlog/stops with a mutex; tests that flip running while a watcher is live use setRunning. - planFake: PlanTasks answers a copy as the store does; setStatus writes a new slice instead of over the one planAppWith handed the surface; pages are guarded, and the program-room test writes them through setPage. Fixes the four held-send races, TestStopOnTheRunsOwnPageRaisesTheCardAndTheCardStopsTheRun, and three more of the same class found on dev: TestAProgramRoomReadsTheLandingTheStoreEndedAhead, TestTheCancelKeyOnAPlanRowEndsItThroughTheStore, TestPOnAPlanRowPausesThenResumes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: change entry for the held-send race fakes (Agent-Field#1836) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: keep the Agent-Field#1836 change entry title under 100 characters Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * tui3: route the plan fakes' test writes through their lock; atomic rail counters Review follow-ups on Agent-Field#1836: - railPlanCounter's rows/pages counts are atomic; they are bumped by the surface's off-loop reads. - planFake gains editRows (in place, keeping planAppWith's aliasing) and setPlan; every direct test write to fake.plan and fake.pages goes through them or setPage. - switchAgent.mu's comment says exactly what it covers. - The change entry's invalidates line is cut to the rules' length and drops surface for this test-only change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…s what it says again (Agent-Field#969) (Agent-Field#1796) * census: the call row carries the demanded set, so served != lane means what it says again (Agent-Field#969) Since the chooser demands the whole admitted set (provider.only with fallbacks off), the router may serve any member of it, so Record.Lane (the ranked head) stopped being the only machine the request would accept. The census read served != lane as the router going somewhere we did not choose, which after the set-demand is often the router choosing a different member of the set we did choose. Add Record.Lanes []string, filled from laneChoice.Only when the demand is still being sent, carrying the whole set when it has two or more members (a one-machine demand is left to Lane alone). The census counts asked != served only when served fell OUTSIDE the admitted set. callrows.Row embeds calllog.Record, so the census reads the new field the day it lands. * docs: change entry for Agent-Field#1796 (demanded set on the call row) * address review: record the demand that actually travelled, not the original choice ZeroPoint95's review on Agent-Field#1796 caught that demandedLanes read the original laneChoice.Only, so a rescue (sends only:[B]) and a narrowed retry (drops a refused machine) recorded the whole original set and misattributed Lane. Capture provider.only as wirePreferences composed it, at encode time, onto the trace; carry it onto the openAttempt so a finish row written after a later attempt re-encoded still describes its own. demandedLanes now reads that composed set, and recordedLane names the single machine a narrowed attempt really demanded rather than the ranked head it recovered from. Adds the two wire-versus-log regression tests the review asked for: a rescue arm records only its one machine, and a narrowed retry does not keep the set it no longer demands and attributes to the machine it does. * address review 2: preserve the demanded set through the hopped close, fix docs ZeroPoint95's second review caught that closeOpenAttempt clears trace.open before recording, so a finish row built on the fallback close read the latest encode's demand rather than the closed attempt's. Carry the attempt's snapshot through recordFacts.demandedOnly and read it off the ended row in bodyDemandedOnly, keyed on ended (set only on that row) so an attempt closed carrying no demand is not handed a later one. Also remove the stale duplicated demandedLanes doc that still described reading laneChoice.Only, and correct the Record.Lanes doc: Lane is a member of the set but not necessarily its first element, since a three-to-two retry can keep the original ranked head as Lane while Lanes names the surviving pair. Adds TestAHoppedAttemptKeepsItsOwnDemandedSetThroughTheClose, which fails without the carry and passes with it. * docs: clarify call demand snapshot comments --------- Co-authored-by: ZeroPoint95 <329227198+ZeroPoint95@users.noreply.github.com>
* docs: describe the built-in coding, security and review specialists * docs: record the specialist README corrections * docs: refine specialist caveat and unwrap touched prose
…nt-Field#1546) (Agent-Field#1842) * session: the daily spend ceiling binds task and errand turns too (Agent-Field#1546) railBlockLocked skipped the daily budget check for InTask runners and the home Errand, and the crew guard that also enforces it is absent under --one-model and for an InTask agent with no crew. So a chat /task past the day's limit, and a task under --one-model, kept spending with no refusal while headless codeaf do and standing firings honoured the limit. Remove the InTask/Errand carve-out so the daily ceiling is checked on every turn-starting path. It is a ceiling read of the shared ledger, never a tally, so a path already held to the crew's own day cap is refused in two places, never charged twice. * docs: change entry for Agent-Field#1842 (daily ceiling on every path) * address review: carry the selected daily budget and spend preauthorization into workers ZeroPoint95's review on Agent-Field#1842 caught that the daily check read the default profile for workers (which carry no ProfileDir), so a worker refused under a higher selected limit and spent past a lower one, and that it re-applied the limit --yes-spend deliberately lifts. - Resolve the daily ceiling once at the root (where ProfileDir is set) and carry it as Config.DailyBudgetUSD; dailyCeilingUSD reads live from the profile for a root and the carried figure for a worker, never a profile at an empty path. - Carry Config.SpendPreauthorized (--yes-spend / CODEAF_PREAUTHORIZE_SPEND=1) into workers; it lifts the daily check and nothing else, matching the crew guard. - Thread both through all three worker constructors: the task-child (task_run.go), the adaptive-run worker (orchestrate.go) and the plan-run bash worker (run.CrewFactory, which gains a preauthorized parameter). Adds regressions: a worker held to its carried selected budget (higher allows, lower refuses) not the default, and preauthorization lifting the daily ceiling while a conversation limit stays in force. * fix: preserve daily budget authority in roots and task checks --------- Co-authored-by: ZeroPoint95 <329227198+ZeroPoint95@users.noreply.github.com>
…ld#1877) * docs: record DeepSWE harness versions and release context * docs: add DeepSWE version evidence change entry (Agent-Field#1877) * docs: use public senior-dev lineage and simplify version records
…#1870) * fix: refresh Codex catalog client version * docs: record Codex catalog version fix for Agent-Field#1870 * test: cover version-gated Codex discovery through both catalog doors Pin the backend fixture independently of the shared client version so reverting the advertised version hides newer models in both direct and translated listings. Preserve visibility filtering and cached reasoning metadata. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Abir Abbas <abirabbas1998@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: build valid SQLite file URIs on Windows * docs: record Windows SQLite URI fix for Agent-Field#1868 * test: preserve POSIX SQLite URIs and cover Windows path forms Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Abir Abbas <abirabbas1998@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…1845) * fix(session): require explicit work orders for auto tasks * docs(changelog): add entry for PR 1845 * test(session): tolerate prompt line wrapping * fix(session): distinguish polite work requests from questions * test(session): cover routing authorization and stopped-result scope Separate feasibility questions from explanation requests in the shared route contract and the searchable chat manual. Pin examples with their complete classification clauses, and prove stopped-result suppression does not block fresh requests or normal remediation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(manual): make stopped-result routing reachable through search Give the stopped-result rule its own section so the manual context includes both the restart guard and the fresh-human-request exception. Pin the actual retrieved answer, since merely finding the long tasks page hid the rule beyond the section limit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(session): judge human steering during stopped-result wakes Read current-turn person provenance and judge the newly consumed instruction, including a verbatim repeat of the stopped request. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(session): scope stopped-result routing to each delivered task Keep attempt snapshots and effective obligations distinct even when sibling tasks inherit the same request. Skip result-only cancelled work before classification, and show both readers only the independent eligible work with explicit cancellation boundaries. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(session): restore task cancellation from its saved ending Derive the stopped runtime flag from the persisted stopped ending. Keep restored cancelled results out of routing while ordinary failed results retain repair eligibility. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(session): limit stopped-result guard to unambiguous result-only wakes Keep dev's routing inputs, floors and rulings whenever a human speaks, results are mixed, or provenance is incomplete. Skip both classifiers only when every delivered result is stopped for the current request in a result-only wake. Remove scoped eligible-work questions, attempt tags and snapshot deduplication. Retain frozen stop provenance and restored cancellation for the stop-only case. Preserve untagged news through batching without changing existing owed asks. Compare production wake, Submit, retry, cancel and recovery probes against dev, and narrow the manual and change entry to the conservative guarantee. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(session): drain steering before reading routes in stopped-wake tests Both fresh-human stopped-wake tests submitted a steer from the answer hook but let the turn race the boundary drain, so CI could count one route reading instead of two. Drain inside the hook, as the mixed-result steering test already does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Abir Abbas <abirabbas1998@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…gent-Field#1884) * docs(agents): say CI is real, Spark is private and no key is normal Agents in cloud sessions kept reporting that the repository has no CI and no Spark. CI is GitHub Actions and runs on every pull request; gh fails there only because its token does not authenticate, so the guide now points at the GitHub MCP tools. Spark is the owner's private machine and was never a step anyone else owed. Add a when-to-run table so cloud sessions lean on touched packages instead of repeating it locally, and drop the PR template's line about the deleted known-red ledger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtiPtzDsHa753NHJBpKYpn * docs(changelog): add entry for PR 1884 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtiPtzDsHa753NHJBpKYpn --------- Co-authored-by: Claude <noreply@anthropic.com>
…gent-Field#1454) The tasks page located task.parallel in category spending, but /settings shows it under Tasks as 'tasks at once' (settings.go's CategoryTasks), so someone following the page searched the wrong section. Name the section and the row exactly as drawn, and add manual probes that reach the tasks page for the setting.
The generic probes only asserted that some section on the tasks page was returned, so restoring the former Spending wording left them green. Put the issue's exact query vocabulary in the section heading and add a focused test that finds that section, requires 'under Tasks as tasks at once', and rejects the former category. The test fails when the old wording is restored and passes with the correction.
santoshkumarradha
force-pushed
the
dev
branch
from
October 24, 2026 21:53
a2f0486 to
d68bcf8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
The tasks manual located
task.parallelin category "spending", but/settingsshows it under Tasks astasks at once(settings.gohasCategory: CategoryTasks,Label: "tasks at once"). Someone following the page searched the wrong section (#1454).internal/manual/chat/tasks.md: the setting now reads "under Tasks astasks at once", naming the section and the row exactly as drawn.internal/manual/chat_test.go: two probes ("where is the tasks at once setting","what section is task.parallel under") assert the question reaches the tasks page.How it was checked
internal/manualdoes not fail on my Windows checkout only because of CRLF working-tree line endings (three unrelated character-count/blank-line tests), which the committed files (LF, confirmed viagit ls-files --eol) and CI never see. So I verified on a clean LF checkout in agolang:1.26Linux container:internal/manualsuite passes with this change applied (git reset --hard+git applythe patch, thengo test ./internal/manual/).TestTheChatManualAnswersTheQuestionsPeopleAsk(which runs the probe table) passes, so both new probes reach the tasks page.Checklist
docs/changes/unreleased/1886-tasks-at-once-manual-category.md..github/known-red.txt.Closes #1454.